Immutable Values ​​in F #

I am just starting out in F # and asking a basic question.

Here is the code:

let rec forLoop body times = if times <= 0 then () else body() forLoop body (times - 1) 

I don’t understand how, when defining a variable, this value and immutability. Here the value is changed in order to loop. How does this differ from a variable in C #?

+4
source share
4 answers

When you make a call (any call), the runtime allocates a new stack stack and saves the parameters and local variables of the called function in the new stack stack. When you make a recursive call, the highlighted frames contain variables with the same name, but they are stored in different frames of the stack.

To demonstrate this, I use a slightly simplified version of your example:

 let rec forLoop n = if times > 0 then printf "current %d" n forLoop body (n - 1) 

Now let's say that we call forLoop 2 from some top-level function or program module. Runtime allocates a stack for the call and stores the parameter value in a frame representing the forLoop call:

 +----------------------+ | forLoop with n = 2 | +----------------------+ | program | +----------------------+ 

The forLoop function prints 2 and continues to work. It makes a recursive call to forLoop 1 , which allocates a new stack stack:

 +----------------------+ | forLoop with n = 1 | +----------------------+ | forLoop with n = 2 | +----------------------+ | program | +----------------------+ 

Since 1 > 0 program enters the then branch again, prints 1 and makes another recursive call to the forLoop function:

 +----------------------+ | forLoop with n = 0 | +----------------------+ | forLoop with n = 1 | +----------------------+ | forLoop with n = 2 | +----------------------+ | program | +----------------------+ 

At this point, the forLoop function returns without any other calls, and the frame stacks are deleted one after another when programs return from all recursive calls. As you can see from the diagrams, we created three different variables that were stored in different frames of the stack (but they were all named n ).

It is also worth noting that the F # compiler performs various optimizations, such as tail-call, which can replace the call and allocation of a new stack frame using a mutable variable (which is more efficient). However, this is just an optimization, and you don't need to worry about it if you want to understand the mental recursion model.

+1
source

he does not change. you are using recursion. that the variable remains unchanged, but one is subtracted and passed to the function. the function in this case is the same.

Stack

will look like

 forLoop body 0 | forLoop body 1 | forLoop body 2 
+5
source

The presented code will not be presented as a for loop in C #, it will be recursive (something like this):

 void ForLoop(int times, Action body) { if (times <= 0) { return; } else { body(); ForLoop(times - 1, body); } } 

As you can see, the times value does not change at any time.

+5
source

Each instance of times in each recursive call is a different object in memory. If body() uses times any way, it captures an immutable value from the current stack frame, which is different from the values ​​in subsequent recursive calls.

The following are C # and F # programs that show one way that the difference is important.

C # program - displays an arbitrary number:

 using System; using System.Threading; class Program { static void ForLoop(int n) { while (n >= 0) { if (n == 100) { ThreadPool.QueueUserWorkItem((_) => { Console.WriteLine(n); }); } n--; } } static void Main(string[] args) { ForLoop(200); Thread.Sleep(2000); } } 

Program F # - always prints 100:

 open System open System.Threading let rec forLoop times = if times <= 0 then () else if times = 100 then ThreadPool.QueueUserWorkItem(fun _ -> Console.WriteLine(times)) |> ignore forLoop (times - 1) forLoop 200 Thread.Sleep(2000) 

The differences arise because the lambda passed to QueueUserWorkItem in C # code captures a mutable variable, whereas in the F # version it captures an immutable value.

+1
source

Source: https://habr.com/ru/post/1306721/


All Articles