[erlang-questions] Re: erlang improvement - objective c (or smalltalk) syntax

Richard O'Keefe ok@REDACTED
Sat Jun 6 07:01:48 CEST 2009

On 6 Jun 2009, at 2:40 am, Thomas Lindgren wrote:
> 1. How do we handle higher-order calls efficiently?

Because Erlang distinguishes between calls to known functions
(identifier begins with a lower case letter) and calls to
unknown functions (identifier begins with an upper case letter),
and because my zero-runtime-cost proposal is just name mangling,
my proposal allows you to use the equivalent of keywords in
calling a higher-order function, but not in calling higher-
order arguments.  That is, you can define

     filter(_, [])    then_map(_) -> [];
     filter(P, [H|T]) then_map(F) ->
	case P(H)
	  of true  -> [F(H) | filter(P, T) then_map(F)]
            ; false ->         filter(P, T) then_map(F)]

What it doesn't provide is anything resembling keyword parameters
in P and F.  Now Smalltalk uses higher-order functions *heavily*.
And it has precisely the same setup: calling known methods and
calling blocks are syntactically different, and there's no analogue
of keywords for calling blocks.  Here's the Smalltalk code I was
imitating above:

     select: selectBlock thenCollect: collectBlock
         r := OrderedCollection new.
	self do: [:each |
	    (selectBlock value: each)
		ifTrue: [r addLast: (collectBlock value: each)]].
	^self pvtAsSpecies: r

Or here is the Smalltalk equivalent of foldl:

     inject: initial into: binaryBlock
	r := initial.
	self do: [:each |
	    r := binaryBlock value: r value: each].

b value: x		is like B(X)
b value: x value: y	is like B(X, Y)

The interesting thing here is that split procedure names give you
_most_ of the benefit of keyword parameters *without* violating
the spirit of functional programming by breaking alpha conversion
or requiring any change to the type system, *but* that it means
that functions don't actually _have_ keywords.

My experience with Smalltalk is that this is not an issue.
Higher-order methods are *called* a lot, but they aren't *written*
very often.  And there really doesn't seem to be much advantage in
higher-order functions that can only be applied to functions with
the right keywords.

To use an imaginary syntax, suppose you have

	zip(_, [], []) -> [];
	zip(F, [X|Xs], [Y|Ys]) ->
	    [F(x=>X, y=>Y) | zip(F, Xs, Ys)].

Now you have a function insert(item=>..., list=>...)
and you have a list of items and a list of lists.
But you cannot give it to zip, because it has the
wrong keywords for its arguments.

If I'm going to write higher-order functions, I really don't
want to have to guess what the caller will want the function
argument's argument names to be.

     filter(P, L) then_map(F)
> 2. How do we handle code change efficiently and correctly?

With the split procedure names proposal, there is absolutely no
difference between what we do now and what we do then.  Code
change that doesn't alter a function name doesn't matter,
whatever the arguments are called.  Code change that does
alter a function name is no harder than it is right now.
> By "efficiently", I mean a solution very close in cost to function  
> calls in the current VM. By "correctly", I mean potential trouble  
> with parameter tags changing in the new version of a module (or,  
> even worse, changing meanings).

The split procedure name approach has zero run time cost and zero
implications for the run time system, including code change.
The down side is that in calling parameters with functional values
you don't get to use keyword-like syntax.

On the other hand, nothing stops you writing

	apply_function(F) first(X) second(Y) ->
	    F(X, Y).

and	zip(F, [X|Xs], [Y|Ys]) ->
	    [apply_function(F) second(Y) first(X) | zip(F, Xs, Ys)]

With apply_function_first_second/3 inlined, there'd be zero cost.
It's just that the keywords would be a property of the way you
chose to call functional data, not a property of the functional value

More information about the erlang-questions mailing list