[erlang-questions] Matthew Sackman's "cut" proposal
Anthony Ramine
n.oxyde@REDACTED
Mon Dec 16 12:28:51 CET 2013
A couple of days ago I had an idea of a syntax that may fit Erlang for partial application.
1/ I wanted something not like cuts, where you have to look very hard to determine the function arity (e.g. count the « _ » in « foo(X, _) ».
2/ I wanted to limit the partial application to trailing arguments, not pass them into arbitrary places like in Elixir where they do stuff like &(foo(&1, X)).
My proposition is:
fun F(A1, .., Am)/N.
Which compiles down to:
fun (Am+1, .., An) -> F(A1, .., Am, Am+1, .., An) end.
This is loosely inspired from Prolog’s higher order predicates.
Pros:
1/ There is an explicit ‘fun’ token which clearly shows a fun is produced here, compared with the implicit enclosing scope of foo(X, _).
2/ There is an explicit arity at the end, compared with the implicit arity of the number of holes in other cut proposals.
3/ It is inspired from the ancestor of Erlang.
4/ That may require a change to the AST, which would be a good occasion to unify the various ‘fun’ AST nodes.
5/ Implementation is *way more* straightforward than the original cut proposal.
Cons:
1/ Should N be the arity of the resulting fun, or the arity of the partially applied function with *all* its arguments included? That may be confusing.
2/ That might require a change to the AST, breaking backwards-compatibility.
I am posting this for people to tell me why I am wrong to think this is a good idea.
Regards,
--
Anthony Ramine
Le 12 juil. 2011 à 05:57, Richard O'Keefe <ok@REDACTED> a écrit :
>
> On 12/07/2011, at 1:15 PM, Tim Watson wrote:
>>
>>> As an occasional Haskell and SML programmer, I am certainly not
>>> against Curried functions. What I *am* against is an approach which
>>> is ugly, confusing, and almost never applicable.
>>>
>>
>> Can't disagree with you there.
>>
>>> If Erlang syntax were generalised to
>>>
>>> ends_with(X)(Y) -> string:equal(string:right(Y, length(X)), X).
>>>
>>> we could eliminate those three tokens.
>>>
>>> What's more, we could do that *WITHOUT* any weird restrictions on
>>> - whether pattern matching is allowed in the fun
>>> - the form of the fun body
>>> - where the arguments appear in the fun body
>>> - the order in which the arguments appear in the fun body.
>>> and *WITHOUT*
>>> - any weird non-intention-revealing tokens, whether '_' or '?'
>>>
>>
>> Yes but you have to admit, it does look a bit odd.
>
> Yes, but that is precisely because it looks just like other languages
> that do Curried functions.
>
> ends_with (x) (y) = rtake y (length x) == x
>
> is perfectly good Haskell, assuming an rtake function, and
>
> fun ends_with (x) (y) =
> List.drop (y, length y - length x) = x
>
> is perfectly good SML, or would be if it didn't crash when y is
> shorter than x.
>
>> Why can't I just
>> use the variable 'Y' and let the compiler figure out that the function
>> signature needs to change?
>
> Because it is only in toy examples that a compiler *could* figure out
> *how* the function signature needs to change.
>
>>> If you want to do Haskell-like things, it doesn't make sense not
>>> to do it in a Haskell-like way, and that is to say that
>>>
>>> <name>(<args1>)(<args2>)...(<argsn>) -> <body>
>>>
>>> is equivalent to
>>>
>>> <name>(<args1>) ->
>>> fun (<args2>) ->
>>> ...
>>> fun (<argsn>) ->
>>> <body>
>>> end
>>> ...
>>> end
>>>
>>> *NO* new tokens!
>>> *NO* weird restrictions!
>>> Good consistency with the way Clean and ML and Haskell do it.
>>> *NO* changes elsewhere in the language.
>>>
>>
>> Great - is it going to get through the eep process? Do we need to vote
>> on it, contribute (e.g., test proposed patches, etc) or whatever?
>
> I don't have time to write up an EEP today, but I'll see what I can do.
> The nice thing about it is that it's entirely in the front end; the
> rest of the compiler doesn't need to know anything about it.
>
>>
>>> Let's see what we have to do now:
>>>
>>> c(F1, F2) -> fun (X) -> F2(F1(X)) end.
>>> c(F1, F2, F3) -> fun (X) -> F3(F2(F1(X))) end.
>>> c(F1, F2, F3, F4) -> fun (X) -> F4(F3(F2(F1(X)))) end.
>>>
>>> doodle(X) ->
>>> F = c(fun do_thing/1,
>>> fun calculate_next_thing/1,
>>> fun get_bored_of_typing_result_x,
>>> fun start_getting_annoyed_with_lazy_programmers/1),
>>> {ok, F(X)}.
>>>
>>> Nope, not hard. Trivial, in fact.
>>
>> Boilerplate.
>
> No, library code, done *ONCE*.
> The only "boilerplate" would be the
> -import(compose, [c/4]). % plus any others you want
> line.
>
> It would, in fact, have precisely the same status as function
> composition in Haskell and SML. Library code.
>
>>> The question is, in a language without static types, how do you
>>> tell the difference between an intentional foo/2 meaning a function
>>> and an erroneous foo/2 that should have been Foo/2, with Foo a
>>> variable bound to a number.
>>
>> We're never going to get static types in Erlang, so I think the answer
>> is that you'd end up with a failing unit or integration test case. Not
>> sure how to do a "raised eyebrow" smiley.
>
> We *have* optional static types in Erlang, but you're right that they
> will probably never be mandatory.
>
> Testing and static checking are complementary tools.
> We need both. Thank goodness we *have* both in Erlang.
>
>> The compiler knows full well that (<module>)<name>/<arity> evaluates
>> to a fun!?
>
> Only if preceded by 'fun'.
>
>
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions
More information about the erlang-questions
mailing list