Explain the expression action, please. F #

let rec fact n = iff ((=) n 1) 1 ((*) n (fact ((-) n 1)));; 
  • Opened chat on F #, so if you have any questions, do not hesitate to ask. Just make me ping in the chat (even if I’m not online) and I’ll answer as soon as possible. - user227049

2 answers 2

The let keyword defines a name for something. Most often it defines a name for values:

 let x = 5 // числу 5 даём имя "x" let y = "abc" // строке "abc" даём имя "y" 

In Russian, let translates roughly as "let" (in the mathematical sense):

 пусть х = 5 пусть y = "abc" 

A separate case is the definition of a name not for a value, but for a function. In this case, immediately after the word let indicate the name of the function, followed by the parameters, separated by spaces:

 let fx = x + 5 

This line defines the function f , which has one parameter x , and the value of the function is calculated by adding five to the parameter value.

The rec keyword in such a definition means that the function is recursive — that is, it is used when its value is increased. For example:

 let rec fx = if x = 1 then 1 else x*(f (x-1)) 

This function has the value 1 when the parameter x=1 , and in other cases its value is calculated by calling this function itself with an argument one less.

The body of your function uses another function iff . This function is not in the standard F # library, so I can only assume that it is defined somewhere above the code.

This function has three parameters:

  • (=) n 1
  • 1
  • (*) n (fact ((-) n 1))

The second parameter is just the constant "1", nothing interesting. But the first and third parameters are expressions in which the operator functions are called in the prefix notation (and not in the infix notation, as is customary for operators). In F #, this is valid and often used. For example, (=) n 1 is the same as n = 1 . Operator = is used here in the prefix notation, for which it must be enclosed in brackets. Similarly:

  • (-) n 1 - the same as n - 1
  • (*) xy - the same as x * y

Thus, the complex notation (*) n (fact ((-) n 1)) is the same as n * fact (n-1) .

Thus, your entire function can be rewritten as follows:

 let rec fact n = iff (n=1) 1 (n * fact (n-1)) 

Note that this entry with iff not equivalent to the same entry with if .. then . The point is in the calculation of the function arguments. In F #, the applicative order of calculating arguments is used — that is, the values ​​of all arguments are calculated before the function is called. In this case, this means that both n=1 and n * fact(n-1) will be calculated before calling the function iff , which means that the call to fact(n-1) will be executed anyway , regardless of n=1 true or not. This will lead to endless recursion, and eventually to a stack overflow.

According to the form of the expression, I assume that its author set himself the goal of imitating Lisp - hence the prefix record of operators. This is what this function will look like in Lisp:

 (defun f (n) (if (= n 1) 1 (* (f (- n 1))))) 

But there is an important difference: the if form in Lisp, like the if .. then construction in F #, is not an ordinary function, but a so-called "special form". When processing special forms, the compiler comes in a special way - in particular, when processing the if form, the compiler will not calculate all three arguments, but instead first calculate the first and then the second or the third (but not both). This will not happen in your example, since iff is just a normal function, which will lead to a stack overflow.

  • Please advise the literature on F # - Dmitry Yarushin
  • one
    If you read in English, then fsharpforfunandprofit.com . Excellent resource, I recommend it to everyone. If you do not read in English, I recommend urgently learn. In our business without English in any way. - Fyodor Soikin
  • @ Dmitry Yarushin, there is a wonderful book by Chris Smith in Russian - “Programming in F #” - user227049

Humanly it will look like this:

  let rec fact n = if n=1 then 1 else n*fact(n-1) 

And if we add fact 5 , then he will consider factorial 5.

came to me)

  • This is not entirely true, and the difference is very critical. See my answer, or rather the last part of it. - Fyodor Soikin