[erlang-questions] Erlang and syntax.

Siraaj Khandkar <>
Wed Feb 26 04:35:47 CET 2014


On 2/24/14, 8:36 PM, Richard A. O'Keefe wrote:
> 
> On 25/02/2014, at 12:38 PM, Siraaj Khandkar wrote:
>> I fail to see the ugliness in:
>>
>>  let dot xs ys =
>>    let rec loop = function
>>      | x::xs, y::ys, s -> loop (xs, ys, s + x * y)
>>      |     _,     _, s -> s
>>    in
>>    loop (xs, ys, 0)
> 
> F# syntax is based on CAML.

The above example is in OCaml, on which F# syntax was initially based
on, not directly on Caml (which preceded OCaml).

http://ocaml.org/learn/history.html


> CAML syntax is based on an early revision of ML
> before the major cleanup that produced SML.

Yes.


> (Not unlike the way C perpetuated a blunder
> that had already been fixed in its ancestor BCPL.)
> 
> Already in this example it shows up.
> There are two functions.
> They have to be declared differently.

They _can_ but don't _have_ to be. I chose to write it that way to match
your examples most closely. Personally, I would rather write it as:

  let dot xs ys =
    let rec loop xs ys s =
      match xs, ys with
      |    [],    [] -> s
      | x::xs, y::ys -> loop xs ys (s + x * y)
      |     _,     _ -> assert false
    in
    loop xs ys 0

or better yet, using stdlib:

  let dot =
    List.fold_left2 (fun s x y -> s + x * y) 0


> 
> There are two kinds of lambda expression:
> 
> 	fun Pat+ [when Guard] -> Expr
> 
> may have multiple *arguments* but not multiple *clauses*,
> while
> 
> 	function [|] Pat [when Guard] -> Expr
>                {  |  Pat [when Guard] -> Expr }...
> 
> may have multiple *clauses* but not multiple *arguments*.
> 
> The calls to loop have parentheses around the arguments
> (to make a tuple, because a function with multiple clauses
> can't have multiple arguments), but the pattern matches
> _don't_ have the parentheses.

This describes the form, but does not make any judgements. Why is that
so terrible? I don't see the problem.

Sure, I can entertain the idea that having an additional form can be
seen as less than perfectly symmetric, but it is still far from the
extreme negativity that you cast when speaking of OCaml (saying it is
uglier than Perl is about as extreme as it gets). There's never a
situation where one _has_ to use the form "function" over "fun", it is
provided merely as an alternative that you _may_ find convenient at
times.


> By the way, tuples-without-
> parentheses are why O'CAML has to use semicolons to
> separate list elements, unlike practically everything else
> where commas are used.

"unlike practically everything else" is a really weak statement on an
Erlang mailing list ;)


> The outer function 'dot' is declared using a let-binding
> 	value_name {parameter}... = expr
> which allows multiple *arguments* but not multiple
> *clauses*, which is why the inner function 'loop'
> *has* to use a lambda-expression.

Again, it doesn't *have* to, but sometimes it is convenient.

Though, frankly, I'm not fully satisfied with function declaration in
any language that I'm familiar with so far. I mostly lean toward the way
it is done in OCaml, because it reinforces the idea that a function is
no different from any other value, so you bind it to a name in exactly
the same way (let name = expr), where as in SML there's a distinction
between (val name = expr) and (fun name arg1 .. argn = expr).

Ideally, I'd probably keep only the "fun" lambda expression form (and
add clauses), because why should there ever be a distinction between a
function declaration and a lambda expression? A named function is just a
lambda attached to a name, after all...

And, before you bring it up as a gold standard, I find Haskell's way
quite unsatisfactory as well. Primarily in two ways: 1) all bindings are
_implicitly_ recursive and 2) no shadowing (which I know, from other
discussions, that you hate, but that is a preference...).


> In contrast, here's the same thing in SML.
> 
> fun dot xs ys =
>     let fun loop (x::xs) (y::ys) s = loop xs ys (s+x*y)
>           | loop _       _       s = s
>      in loop xs ys 0
>     end
> 
> In SML, functions can have BOTH multiple arguments and
> multiple clauses.

But not guards...

As a user of both languages, I generally agree - SML is the more
elegantly designed language [1]. It was designed to be so, where as
OCaml evolved more organically (much like Erlang has), as a tool for
implementation of Coq, without a formal definition, but nonetheless
rigorously worked out theory behind the language additions.

There has been a lot of interesting progress in both, the OCaml
language and ecosystem, since the last time you seriously looked at it
(which I can only imagine must have been a while):

- recursive modules
- private types (which differ from abstract types by allowing reading
but still not constructing the representation)
- locally abstract types (which allow "shared secrets", that Harper
said were only possible in SML [2])
- first-class modules
- GADTs!
- a really awesome package manager [3]

More here: http://caml.inria.fr/pub/docs/manual-ocaml-400/manual021.html


[1]: Though I do find some things unpleasant, mainly the lack of
syntactic distinction between constructors and identifiers.

[2]:
http://existentialtype.wordpress.com/2012/12/03/exceptions-are-shared-secrets

[3]: https://opam.ocaml.org


>>> Does anyone else remember my proposal that would have had us
>>> write this as
>>>
>>>   dot(Xs, Ys) ->
>>>     (S where S = 0 then S+X*Y || X <- Xs & Y <- Ys).
>>
>> Where is S coming from here?
> 
> From the 'where' part.  It's
>    ( <result> where <binding>,... || <generators and tests> )
> and a <binding> is
>    <pattern> = <initial value> [then <subsequent value>].
> 
> 'let P = E0 in E1' and 'E1 where P = E0' are traditional
> alternatives in functional programming.
> 
> It's a cross between Lisp's DO (the <binding> part and the
> <result> part) and comprehensions (the <generators and tests> part).

I really like the idea of being able to express "X <- Xs & Y <- Ys",
but, even with the explanation, I still find the left hand side quite
unintuitive.



More information about the erlang-questions mailing list