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

Tim Watson watson.timothy@REDACTED
Tue Jul 12 03:15:35 CEST 2011


>> For me, the compelling reason to have *something* like this is that
>> function composition and partial application are the bread and butter
>> of my programming style,
>
> This is not unlike saying "assignment and goto are the bread and
> buffer of my C style, so Erlang should support assignment and goto".
> Function composition and partial application are not part of
>>>Erlang's<< native style.
>
> Again, the old joke:
>        Doctor: What's the problem?
>        Patient: It hurts when I do <this>?
>        Doctor: Then don't do <that>.
>
> If you try to write Erlang as if it were SML (or CML),
> it's obviously going to hurt.  So the answer is don't do that.
>

Ok I can see your point, and to be fair I nowadays spend more time in
Erlang than OCaml so I've gotten used to not doing <that> to some
extent.

>> and in Erlang they both prove to be rather,
>> what shall we say, wordy? For example, consider this function (a
>> hamcrest matcher) which isn't too bad at all, but is indicative of the
>> amount of noise we have to deal with:
>>
>> -spec(ends_with/1 :: (string()) -> fun((string()) -> boolean())).
>> ends_with(X) ->
>>    fun(Y) -> string:equal(string:right(Y, length(X)), X) end.
>
> The amount of "noise" here is precisely three tokens: 'fun' '->' 'end'.
> Your suffering cannot be said to be extreme.
>

It wasn't an horrific example, as I mentioned, but was meant to be indicative.

> 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. Why can't I just
use the variable 'Y' and let the compiler figure out that the function
signature needs to change? This was kind of my point - although I went
around the houses as was duly (and correctly) chastised for doing so -
can the compiler do more of the leg work.

>> Not personally, I would much sooner have the compiler deal with the
>> anonymous function machinery for me:
>>
>> -spec(ends_with/1 :: (string()) -> fun((string()) -> boolean())).
>> ends_with(X) ->
>>    string:equal(string:right(?, length(X)), X) end.
>
> It would be much much better as
>
> ends_with(Suffix)(String) ->
>    string:equal(string:right(String, length(Suffix)), Suffix).
>
>> discussing the syntax - I could happily go with any marker-character
>
> My argument is that ANY marker character is wrong because
>  - you can't nest closures that way (does this ? belong to the
>   inner fun or the outer one?)
>  - you can't read the intent of a parameter from a weirdo like
>   '?' the way you can from a name like String
>  - you have all those other weird restrictions I mentioned above

I can understand your dislike of using a marker character.

> 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?

> 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. Might as well type it out inline. There have to be neater
ways of composing and currying. I like with your <name>(a1)(a2)(a3) in
that it at least makes the application (order) visible and obvious.

>>
>> I can't understand why the parser requires me to type "fun M:F/A" when
>> the "/" character clearly indicates that I'm referencing a function in
>> a special way.
>
> 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.

>
> What _I_ don't understand is why fun F/2 is not allowed with F a
> variable.
>

Yeah, most annoying.

>> And if the compiler can recognise a reference to a
>> function (local or otherwise), then why not have it recognise "+" as
>> an operator for chaining function calls?
>
> Well, I've done enough mathematics to be driven screaming with rage
> up the nearest handy wall at any use of "+" for an operation that is
> not commutative.  The operation you want here is often called ";" in
> denotational semantics.  It's (F;G) X = G(F(X)).

Sheesh I hadn't thought about commutativity - yes '+' is a bad choice
in light of that. We aren't going to get ';' used in this way are we,
given it's existing role in the syntax. Perhaps avoiding overloaded
operators would be sensible, though I have to admit that Haskell's use
of '.' is very clean, though inadmissible for the same reason.

>
> Again, in general the compiler *CANNOT* recognise a reference to a
> function.  Haskell and SML manage that by means of type checking,
> and *they* don't overload function composition with any other
> operation.
>

The compiler knows full well that (<module>)<name>/<arity> evaluates
to a fun!? I'm aware that we don't have type checking at compile time.
I'm also vaguely aware of how things work in Haskell/SML. What I'm not
aware of is what the combination of *ASTERISK AND CAPITAL LETTERS*
means. ;-)



More information about the erlang-questions mailing list