Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Partial function application compiles to wrong erlang #44

Open
michallepicki opened this issue Jan 23, 2021 · 9 comments
Open

Partial function application compiles to wrong erlang #44

michallepicki opened this issue Jan 23, 2021 · 9 comments
Labels
bug Something isn't working compiler Related to the OCaml to Erlang compiler

Comments

@michallepicki
Copy link
Contributor

michallepicki commented Jan 23, 2021

Describe the bug
A simple function that taking no arguments in Caramel, that only runs Io.format, compiles to invalid erlang that says it is taking two arguments, which erlang/OTP cannot compile.

To Reproduce

$ caramelc --version
0.0.14+git-27bc02d
$ cat sweetness.ml 
let text () = "Hello, world!"

let hello () = Io.format (text ())
$ caramelc compile sweetness.ml
Compiling sweetness.erl OK
$ cat sweetness.erl 
% Source code generated with Caramel.
-module(sweetness).

-export([hello/2]).
-export([text/0]).

-spec text() -> binary().
text() -> <<"Hello, world!">>.

-spec hello(ok, list(any())) -> ok.
hello() -> io:format(text()).


$ erl
Erlang/OTP 23 [erts-11.1.6] [source] [64-bit] [smp:6:6] [ds:6:6:10] [async-threads:1] [hipe]

Eshell V11.1.6  (abort with ^G)
1> c(sweetness).
sweetness.erl:4: function hello/2 undefined
sweetness.erl:10: spec for undefined function hello/2
sweetness.erl:11: Warning: function hello/0 is unused
error

Expected behaviour
.erl gets created with

-export([hello/0]).

-spec hello() -> fun((list(any())) -> ok).
@michallepicki
Copy link
Contributor Author

michallepicki commented Jan 23, 2021

I think it may be because I thought there is an Io.format function that takes one argument but there's only a two argument version? Still I think this should not be the result, I don't know where the ok in spec comes from and why spec args do not align with function args. I don't know much Ocaml but should that compile to something like

-export([hello/1]).
-spec hello(list(any())) -> ok.
hello(args) -> io:format(text(), args).

?
Or

-export([hello/0]).
-spec hello() -> fun((list(any())) -> ok).
hello() -> fun
     args -> io:format(text(), args)
   end.

?

@michallepicki michallepicki changed the title Function using Io.format compiles to wrong erlang Function using Io.format with only one argument compiles to wrong erlang Jan 23, 2021
@michallepicki
Copy link
Contributor Author

Also tried on 0fe81e7, same result

@leostera leostera added bug Something isn't working compiler Related to the OCaml to Erlang compiler labels Jan 23, 2021
@leostera
Copy link
Owner

Thanks for filing this!

Since Caramel is an ML, we do partial application by default. When you called Io.format x what you get back is a function 'a list -> unit.

You're correct that this is a bug because the signature of hello/0 is incorrect.

The right signature should be hello() -> fun( (list(_)) -> ok ).

@leostera
Copy link
Owner

leostera commented Jan 23, 2021

-export([hello/1]).
-spec hello(list(any())) -> ok.
hello(Args) -> io:format(text(), Args).

This doesn't quite track because in the Caramel source you still have to call hello () args, and that unit is being translated as an ok. Empty tuples {} in Erlang just don't aren't a convention.

@leostera
Copy link
Owner

leostera commented Jan 23, 2021

-export([hello/0]).
-spec hello() -> fun((list(any())) -> ok).
hello() -> fun (Args) -> io:format(text(), Args) end.

This would be the Right Thing ™️, but is highly unidiomatic Erlang code.

@michallepicki michallepicki changed the title Function using Io.format with only one argument compiles to wrong erlang Partial function application compiles to wrong erlang Mar 3, 2021
@nicobao
Copy link
Contributor

nicobao commented Mar 13, 2021

I look into this.

@nicobao
Copy link
Contributor

nicobao commented Mar 14, 2021

-export([hello/0]).
-spec hello() -> fun((list(any())) -> ok).
hello() -> fun (Args) -> io:format(text(), Args) end.

This would be the Right Thing tm, but is highly unidiomatic Erlang code.

So I suppose I should implement the Right Thing, even if it is highly unidiomatic?

@nicobao
Copy link
Contributor

nicobao commented Mar 14, 2021

I tried:

nicolas@localhost:~/test-caramel$ caramel --version
0.1.0+git-23d695b

test_hello.ml

let text () = "Hello World" in

let hello () = Io.format (text ()) in
hello ()

then
caramel compile test_hello.ml

which leads to no error, a test_hello.cmi file but no erl file.

If I try with

test_ocaml.ml

let text () = "Hello World" in

let hello () = print_endline (text ()) in
hello ()

and I do ocaml test_ocaml.ml, it returns Hello World.

Is that normal that in operator is not accepted top-level?

@leostera
Copy link
Owner

@nicobao yes, I think they're ignored but they probably should fail with an error (just like let rec within a let).

The automatic uncurrying can be done (as shown by BuckleScript), but that's a larger task than undoing the work I did for it. Let's start there, translating the functions as they are, and we can optimize later 🙌🏽

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working compiler Related to the OCaml to Erlang compiler
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants