-
Notifications
You must be signed in to change notification settings - Fork 47
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
Fails to compile when applying the result of a function #56
Comments
I think the first arity error makes sense. What if there was also a I don't know why the parenthesized version does not work. Spelling it out works:
The exact error
|
Indeed, I'd mistakenly thought that only one function (regardless of arity) was allowed per name per module, therefore auto-currying would be possible, but I see that this was an oversight that is being corrected. I agree with @danabr that multiple arity functions and auto-currying do not mix well. Scala has a special syntax for curried functions: http://docs.scala-lang.org/tutorials/tour/currying.html but I think that would be unnecessarily complicated. I guess my concern is that people familiar with other ML languages may be surprised by the lack of automatic currying, and things like point-free style are difficult to implement without it. I suppose the typer could allow automatic currying if one and precisely one variant only of a function were defined, and throw an appropriate error in the case that currying would lead to ambiguous use. I guess the sweet spot is how to be a nice Erlang citizen while being as nice an ML as possible :) The problem with not being able to apply the result of functions stems from here: https://github.com/alpaca-lang/alpaca/blob/master/src/alpaca_parser.yrl#L404 As far as I understand it there's no rule to match applying on a general expression (specifically here, an apply expression). I wrote a test for the case and managed to write a rule in the parser, but I think that the |
I'm completely open to a discussion about multiple arity versions vs automatic currying, I just stuck that "fix" in today because it felt a little closer to Erlang and I was writing some Alpaca that could take advantage of it :) If it makes sense to back that out in favour of auto-currying I don't really have a problem with it tbh. Would be curious to hear arguments for/against. As for the AST changes I think we're going to end up wrapping the returns in core-erlang let-bindings in the code generation stage as the following:
becomes this in core Erlang (some output redacted for brevity):
In this case should we have a different AST node for application of expressions or replace |
I like the latter approach - the AST node would have a 'function' part which is either a name of a function or an expression which yields a function. I'll present my argument here for my preferences on autocurrying. I'm very much in favour of autocurrying. SML, Miranda, Haskell, Elm and OCaml all implement it, and it makes the language very malleable. I propose we allow autocurrying and multiple arity functions, but if more than one variant of a function is defined and not enough arguments are provided to match any variant, the typer errors with an error message explaining that autocurrying is disallowed in these circumstances (and suggest renaming the variants). If push came to shove, I'd personally prefer autocurrying to multiple arity. I don't think the loss is too great - you just have to give functions different names - but you gain a great deal. One example is that a function like -- Imaginary function filter == (a -> bool) -> list a -> list a
let filtered =
[1, 2, 2, 3, 3, 3] |> filter ((==) 2)
-- result: filtered == [2, 2] ...so this imaginary filter function takes a predicate function that returns a bool, a list of 'a and returns a list of 'a. We call filter with only one argument, so we get a function that is 'waiting' for a list. Counter-arguments for me are - we're in Erlang land and multiple arity is a natural fit there. Also we can emulate autocurrying above by providing a standard library with 'pre-curried' functions with different arities and functions for currying, and at worst we can always return / wrap using anonymous functions, once those are implemented. It's also possible to get carried away with techniques like point free style which can lead to terse and hard to read code. |
I'm quite reluctant to remove differing arity definitions for the same named function since it's common enough in the Erlang world that removing it might be a stumbling block for those coming from there but autocurrying makes enough sense to make it happen. My primary concern is bounding ambiguity - your proposal to simply drop out with a type error when we don't have enough information to make a decision seems pretty reasonable to me provided we make things clear enough for a user. So the following would generate an error along the lines of
While the following would not:
Thoughts? Am I clinging too tightly to the differing arity thing? |
I think that looks great. I'm sure if it ever does get confusing there will be ways of disambiguating, syntactically if needs be. |
I've opened issue #74 to address the automatic currying piece of this so we can fix the basic expression application problem on this one. |
When a function returns a function, it cannot be applied (in MLFE - from Erlang, the resulting function can be called).
From Erlang, it works fine:
But in MLFE, this won't compile:
curried 1 2 3
resulting in a compiler error:Using parens (to prevent what I presume is greedy application above) produces a different error:
The text was updated successfully, but these errors were encountered: