[erlang-questions] Matthew Sackman's "cut" proposal

Anthony Ramine <>
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 <> 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
> 
> http://erlang.org/mailman/listinfo/erlang-questions




More information about the erlang-questions mailing list