What's the reason of 'let rec' for impure functional language OCaml?

前端 未结 6 1848
梦谈多话
梦谈多话 2021-02-02 06:54

In the book Real World OCaml, the authors put why OCaml uses let rec for defining recursive functions.

OCaml distinguishes between nonrecurs

6条回答
  •  不要未来只要你来
    2021-02-02 07:48

    It's not a question of purity, it's a question of specifying what environment the typechecker should check an expression in. It actually gives you more power than you would have otherwise. For example (I'm going to write Standard ML here because I know it better than OCaml, but I believe the typechecking process is pretty much the same for the two languages), it lets you distinguish between these cases:

    val foo : int = 5
    val foo = fn (x) => if x = foo then 0 else 1
    

    Now as of the second redefinition, foo has the type int -> int. On the other hand,

    val foo : int = 5
    val rec foo = fn (x) => if x = foo then 0 else 1
    

    does not typecheck, because the rec means that the typechecker has already decided that foo has been rebound to the type 'a -> int, and when it tries to figure out what that 'a needs to be, there is a unification failure because x = foo forces foo to have a numeric type, which it doesn't.

    It can certainly "look" more imperative, because the case without rec allows you to do things like this:

    val foo : int = 5
    val foo = foo + 1
    val foo = foo + 1
    

    and now foo has the value 7. That's not because it's been mutated, however --- the name foo has been rebound 3 times, and it just so happens that each of those bindings shadowed a previous binding of a variable named foo. It's the same as this:

    val foo : int = 5
    val foo' = foo + 1
    val foo'' = foo' + 1
    

    except that foo and foo' are no longer available in the environment after the identifier foo has been rebound. The following are also legal:

    val foo : int = 5
    val foo : real = 5.0
    

    which makes it clearer that what's happening is shadowing of the original definition, rather than a side effect.

    Whether or not it's stylistically a good idea to rebind identifiers is questionable -- it can get confusing. It can be useful in some situations (e.g. rebinding a function name to a version of itself that prints debugging output).

提交回复
热议问题