Immutable variables in OCaml

梦想与她 提交于 2021-01-27 06:32:12

问题


I'm learning OCaml, and I'm a bit confused with the immutability of variables. According to the book I'm reading, variables are immutable. So far so good, but why on Earth can I do this:

let foo = 42
let foo = 4242

What am I missing??


回答1:


I think the best way to explain is with an example. Consider this code (executed in the OCaml REPL):

# let foo = 42;;
val foo : int = 42

# let return_foo () = foo;;
val return_foo : unit -> int = <fun>

# let foo = 24;;
val foo : int = 24

# return_foo ();;
- : int = 42

The above code does the following:

  1. Binds 42 to the name foo.
  2. Creates a function return_foo () that returns the value bound to foo.
  3. Binds 24 to the name foo (which hides the previous binding of foo).
  4. Calls the return_foo () function, which returns 42.

Compare this with the behaviour of a mutable value (created using ref in OCaml):

# let foo = ref 42;;
val foo : int ref = {contents = 42}

# let return_foo () = !foo;;
val return_foo : unit -> int = <fun>

# foo := 24;;
- : unit = ()

# return_foo ();;
- : int = 24

which:

  1. Creates a mutable reference containing 42 and binds it to the name foo.
  2. Creates a function return_foo () that returns the value stored in the reference bound to foo.
  3. Stores 24 in the reference bound to foo.
  4. Calls the return_foo () function, which returns 24.



回答2:


The name foo is first bound to an immutable value 42 and later it is rebound to another immutable value 4242. You can even bind the same name to variables of different types. In OCaml we are talking not about mutability of a variable, but about a mutability of a value. For example, if you bind foo to an array of values, this would be the same name, but bound to a mutable data, so that the value of a variable can change in time. Finally, each new binding just hides the previous one, so the original foo is still bound to 42, but it is invisible and will garbage collected.

Maybe a little example will clarify the idea:

let example () = 
  let foo = 42     in (* 1 *)
  let foo = 4242   in (* 2 *)
  let foo = [|42|] in (* 3 *)
  foo.(0) <- 56       (* 4 *)

It might be easier to have the following mental model:

                  (*1*)  +--------+
                  +----> |   42   |
+------------+    |      +--------+
|            +----+
|    foo     +----+      +--------+
|            |    +----> |  4242  |
+---------+--+    (*2*)  +--------+
          |
          |       (*3*)  +--------+
          +------------> |[| 42 |]|
                  (*4*)  +--------+

On lines 1 and 2 we just bind a variable foo to two different values. On line 3 we bind it to an array that contains one element. On line 4, we change the value, and foo is still bound to the same value, but the value contains different datum.

I hope I didn't confuse you even more ;)




回答3:


The usual form of let is the let ... in expression, where you define a variable binding, which only exists in the inside of the body of the let. The body of the let is a new scope.

let x = 42 in (* body here *)

Here the "body" of the let is a new scope that is different from the one outside, with all the variables from the outside with an additional local variable x that is only defined in the body of this let.

Now you are talking about lets at the top level of the file. These look a little different syntactically (there is no in), but really they are the same, with the "body" being the rest of the file. So here you can think of the rest of the file after the let as a new scope, with x being a local variable of this scope. So your code is equivalent to this:

let foo = 42 in (
  let foo = 4242 in (
    (* rest of file *)
  )
)

Here your inner let binds a local variable that has the same name as a variable that already exists in the outer scope. That doesn't matter. You are binding a new variable in an inner scope. If it happens to have the same name as a variable in an outer scope, then code in the inner scope referencing that name will refer to the innermost binding. The two variables, however, are completely independent.

In a C-like language, it would be something like this:

{
    const int foo = 42;
    {
        const int foo = 4242;
        // rest of code here
    }
}

See? There is no assignment to any variables here.



来源:https://stackoverflow.com/questions/35641464/immutable-variables-in-ocaml

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!