leostera / caramel

:candy: a functional language for building type-safe, scalable, and maintainable applications
https://caramel.run
Apache License 2.0
1.05k stars 25 forks source link

Forbid let rec inside of a let binding #13

Closed leostera closed 3 years ago

leostera commented 3 years ago

The following OCaml

let let_rec () =
  let rec f x = f (x + 1) in
  f 1

should emit a compilation error that let rec bindings inside of a function definition are not allowed. It should suggest the programmer to just define an auxiliary function outside, and it can reuse the name of the let rec binding for it. For example:

We found a `let rec` binding for `f` inside of `let_rec/0` and these are not supported.
Did you mean to define a `f_aux` outside instead?

Instead it compiles to this Erlang:

let_rec() ->
  F = fun (X) -> f(erlang:'+'(X, 1)) end,
  F(0).

which is misleading at first, but we can tell is wrong because it is trying to recurse into the function f/1 which is in fact not defined anywhere.

This can be fixed in the mapping of Texp_let values by checking if the recursive flag is set to true and extending the OCaml_to_erlang.Error module with the right message.

Other notes

I'd like to enable this pattern in the future, as it could be done translating the expression to:

let_rec() ->
  RecF = fun(G) -> fun (X) -> (G(G))(X+1) end end,
  F = RecF(RecF),
  F(0).

which could be standardized as part of the caramel.erl runtime libraries:

let_rec() ->
  F = caramel:letrec1(fun (F, X) -> F(X + 1) end)
  F(0).

But I fear this would not be as useful right now. We'll see later!