[erlang-questions] LFE - Lisp Flavoured Erlang released

2,009 views
Skip to first unread message

Robert Virding

unread,
Mar 1, 2008, 8:00:06 PM3/1/08
to Erlang Questions
I have finally released LFE, Lisp Flavoured Erlang, which is a lisp syntax front-end to the Erlang compiler. Code produced with it is compatible with "normal" Erlang code. The is an LFE-mode for Emacs and the lfe-mode.el file is include in the distribution. Most things seem to work but some things have not been done yet:

- The interpreter does handle recursive letrecs, binaries, receive or try.
- There is no lisp shell.
- Documentation!

Yet. The system will be updated as new features are added. This is the 1st release so there is much left to do.

I have include the existing documentation lfe_guide.txt in this mail. There are a number of LFE test files and a version of the LFE interpreter written in LFE as examples of code. There are also a number of issues which need to be decided for the next version and I have included a file lfe_issues.txt which describe them in this mail. Both files are in the distribution.

Note that while this this lisp has been inspired by Scheme (one of the issues) it is a NOT Scheme, it is Erlang with a lisp syntax and many nice lisp features. Not for that matter is it Common Lisp. In fact features of the Erlang engine mean that it is actually impossible to implement full Scheme of CL. No, they shouldn't be changed or added.

It was quite writing Erlang code in lisp and I could easily consider using a lisp syntax for Erlang. I suppose it depends where your preferences lye. It was also easy to get into the traditional lisp habit of using long names for everything which I personally think is not a Good Thing. Perhaps we should do AFE, Arc Flavoured Erlang, instead? Although I think they have gone too far and missed what makes programs easy to read.

Macros are very nice, and it is easy to generate LFE code, which is one of the benefits of lisp syntax.

LFE also shows that it would probably be possible to write other front-ends inspired by other languages, though why anyone should want to I don't know. Perhaps back to a real Prolog syntax again.

The system can be found in the "User Contributions" section at trapexit.org, http://forum.trapexit.org/viewtopic.php?p=40268#40268.

lfe_guide.txt
lfe_issues.txt

Tim Fletcher

unread,
Mar 2, 2008, 4:46:16 AM3/2/08
to Erlang Questions
> I have finally released LFE, Lisp Flavoured Erlang, which is a lisp syntax
> front-end to the Erlang compiler.

Does it require a particular version of Erlang?
_______________________________________________
erlang-questions mailing list
erlang-q...@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions

Richard Carlsson

unread,
Mar 2, 2008, 7:15:31 AM3/2/08
to Robert Virding, Erlang Questions
Robert Virding wrote:
> Function bindings
> -----------------
>
> Core Erlang (and Erlang and the BEAM) separate variable and function
> bindings. A function binding has a name and an arity, this is a result
> of allowing different functions to have the same name but different
> number of arguments. Also there is no concept of a function reference
> built into the Core and BEAM. It is therefore impossible to get a
> reference to a function and pass it around, creating a fun which calls
> this function is not the same thing. So code like:
>
> In CL: (funcall #'cons a b)
> In Scheme: (let ((my-cons cons)) (my-cons a b))
>
> CANNOT work in Erlang.

I think you can relax, Robert. This is not a problem.

In plain Erlang, you'd write

MyCons = fun cons/2,
MyCons(A,B)

In Core Erlang, you write it like this:

let MyCons = 'cons'/2 in apply MyCons(A, B)

Neither of these things mean that you'll necessarily get another
closure that will delegate the call - that's an old implementation
detail, which is not universally valid anymore. (E.g., with inlining
enabled, this will reduce to a direct call "cons(A, B)".) And in
particular, there is just a single variable namespace.

You're right that Core Erlang has no special notation ("fun f/N") for
referring to a function (as opposed to defining it) - that's because the
keyword "fun" is not needed. Core Erlang has two flavours of variables:
normal Erlang-style variables, and 'atom'/integer function names. (We
could actually have used only the first form, but then the Core Erlang
code would be harder to understand, and the export section would have to
look something like "export [ F17 as 'foo'/2, F32 as 'bar'/1, ... ]".)
You can only define function-name variables in letrec-expressions, not
in let-expressions, but this is no limitation in general, since you can
easily bind a plain variable to a function-name variable, as above.

The main point here is: when you see some expression "'f'/3" in Core
Erlang or "fun f/3" in Erlang, think of it as just a name, a variable.
Forget about how "fun f/3" was originally implemented. This is one of
the big things about Core Erlang: except for when you need to create
names of exported functions, that will be visible outside the module,
a variable is just a reference to some value, functional or not, and
it does not matter whether it was defined in a letrec or a let. This
makes it much easier to do transformations like inlining on the Core
language level.

/Richard

PS. I know that it's not easy to grok the full consequences of the Core
Erlang specification; one has to sort of clear one's mind and start from
scratch - if the spec doesn't prohibit something, then it should just
work (assuming that the compiler doesn't have a bug or is incomplete).

[http://www.it.uu.se/research/group/hipe/cerl/doc/core_erlang-1.0.3.pdf]

If you need human assistance to interpret some detail, just mail me.

Roberto Saccon

unread,
Mar 2, 2008, 3:22:58 PM3/2/08
to Richard Carlsson, Erlang Questions
Amazing ! Thanks for sharing. I have a little question about an
implementaiton detail:

Is there a particular reason for setting the linenumber to 6666 in
annotations where there is no associated Lisp source code ?

Roberto

--
Roberto Saccon
http://rsaccon.com

Robert Virding

unread,
Mar 2, 2008, 5:10:12 PM3/2/08
to Erlang Questions
OK, some points I forgot to mention:

- Of course, the interpreter does *NOT* handle recursive letrecs, binaries, receive or try. Yet.
- The token syntax is specified in leex but I have included a copy of a generated erlang file.
- The compiler is "sensitive" to some errors and will occasionally crash, though it should only generate correct code.
- The line numbers used in error messages are the line of the beginning of the form in which the error occurs. As the forms are truly raw data this was the best way I could get line numbers in.

The answer to Roberto's question about line number 6666 is just I wanted a big number which was guaranteed not to clash with users code. And 666 seemed to small. :-)

- I have been thinking about a way to load a module into the shell (when it exists) and I think I have worked out a way to do it. With a little bit of luck it should also support macros. You might actually be able to save a module from the shell as well but I have not thought this through properly yet.

Please report bugs and other mis-features and I will fix them as soon as I can. Unfortunately I am using a toy computer so sending out patches will be difficult.

Robert

Robert Virding

unread,
Mar 2, 2008, 5:15:11 PM3/2/08
to Tim Fletcher, Erlang Questions
On 02/03/2008, Tim Fletcher <two...@gmail.com> wrote:
> I have finally released LFE, Lisp Flavoured Erlang, which is a lisp syntax
> front-end to the Erlang compiler.


Does it require a particular version of Erlang?

It was developed on R12B-0 but I don't think there should be any trouble on running it on R11B. I don't think that Core has changed very much, at least at the level I am using it. Let me know if you detect anything strange.

Robert


Kostis Sagonas

unread,
Mar 2, 2008, 5:49:10 PM3/2/08
to Erlang Questions
Robert Virding wrote:
>
> Please report bugs and other mis-features and I will fix them as soon as
> I can.

Well, since you asked for it, at a click of a button dialyzer reports
the following:

lfe_scan.erl:215: The pattern <Rest, Line, {'end_token', T}, Ts> can
never match the type <_,_,'error' | 'skip_token' | {'error',[32 | 97 |
99 | 101 | 103 | 104 | 105 | 108 | 114 | 116,...]},_>
lfe_scan.erl:164: The pattern <Rest, Line, {'end_token', T}> can never
match the type <_,_,'error' | 'skip_token' | {'error',[32 | 97 | 99 |
101 | 103 | 104 | 105 | 108 | 114 | 116,...]}>
lfe_scan.erl:118: The pattern <Rest, Line, {'end_token', T}, Ts> can
never match the type <_,_,'error' | 'skip_token' | {'error',[32 | 97 |
99 | 101 | 103 | 104 | 105 | 108 | 114 | 116,...]},[{atom(),_} |
{'number',_,_} | {'string',_,[any()]} | {'symbol',_,atom()}]>
lfe_scan.erl:255: The pattern <Rest, Line, {'end_token', _T}, Error> can
never match the type <_,_,'error' | 'skip_token' | {'error',[32 | 97 |
99 | 101 | 103 | 104 | 105 | 108 | 114 | 116,...]},_>

lfe_macro.erl:490: The pattern {'yes', _} can never match the type
'error' | {'ok',_}
lfe_macro.erl:489: The pattern {'yes', _} can never match the type
'error' | {'ok',_}


The first set is just dead clauses. The second set, is a mismatch of the
return value of a function.

Dialyzer also reports some more additional warnings which are also
reported by the BEAM compiler, so I am suppressing these.

Cheers,
Kostis

Robert Virding

unread,
Mar 2, 2008, 6:04:22 PM3/2/08
to Kostis Sagonas, Erlang Questions

The first lot from lfe_scan are just handling a possible legal case which can be used in leex but which I don't use here. You can return a token {end_token,Token} which means that if you use the tokens/2/3 call then it will read tokens up to and including an {end_token,...}. Perfect for Erlang '. '.

The second one was a bug, now fixed, thank you.

Dialyzer also reports some more additional warnings which are also
reported by the BEAM compiler, so I am suppressing these.

None of the compiler warnings are interesting so I ignore them.

Robert

Yariv Sadan

unread,
Mar 2, 2008, 8:44:42 PM3/2/08
to Robert Virding, Erlang Questions
Robert, this is very cool. I already started playing with LFE and it's
great. Thanks a lot for sharing it.

I have a couple of suggestions:

- it would be nice to have a preprocessor/parse transform that converts the form

(foo:bar baz ..)

to

(: foo bar baz ...)

I find the former much more readable.

- It would like to have an Erlang-style '=' operator for binding
instead of (let). The main difference is in the number of parentheses
and the scoping rules. So, instead of

(let ((a 1) (b 2)) (+ a b))

you could write

(= (a 1) (b 2))
(+ a b)


- String literals should be interpreted as literal lists rather than
sexps. It seems redundant to write a single quote before a string
literal.

- It would be great to have syntax for multi-line strings and binaries.

- Distributing LFE under a standard open source license would
encourage its adoption and foster community contributions.
lfe_scan.erl has this license notice:

%%% (C)Robert Virding. This stuff is mine, distributed without
%%% warranty "as is" and may not be used commercially without letting
%%% me know.

This wording is ambiguous. Is the only requirement to using LFE
commercially to let you know, or it it required to buy a license for
commercial use? What happens to user contributions? Etc.

Regards,
Yariv


2008/3/1 Robert Virding <rvir...@gmail.com>:

Mikael Pettersson

unread,
Mar 3, 2008, 3:25:56 AM3/3/08
to Yariv Sadan, Erlang Questions
Yariv Sadan writes:
> Robert, this is very cool. I already started playing with LFE and it's
> great. Thanks a lot for sharing it.
>
> I have a couple of suggestions:
>
> - it would be nice to have a preprocessor/parse transform that converts the form
>
> (foo:bar baz ..)
>
> to
>
> (: foo bar baz ...)
>
> I find the former much more readable.

This I can agree with, as long as we're only talking about
literal module and function names, not general expressions.

> - It would like to have an Erlang-style '=' operator for binding
> instead of (let). The main difference is in the number of parentheses
> and the scoping rules. So, instead of
>
> (let ((a 1) (b 2)) (+ a b))
>
> you could write
>
> (= (a 1) (b 2))
> (+ a b)

NO! Absolutely no fricking way.
The way Erlang (ab)uses the '=' sign to do bindings is
IMNSHO one of the ugliest flaws in the language, in part
because it isn't structurally lexical scoped (bindings
flow /out/ of expressions, not just into them).

The point of Lisp/Scheme-like S-expression syntax is not
just using parenthesis for grouping, but also using the
structure to express scoping. LET-expressions do that,
your '=' abuse would not.

Robert Virding

unread,
Mar 3, 2008, 3:20:30 PM3/3/08
to Yariv Sadan, Erlang Questions
On 03/03/2008, Yariv Sadan <yariv...@gmail.com> wrote:
Robert, this is very cool. I already started playing with LFE and it's
great. Thanks a lot for sharing it.

I have a couple of suggestions:

- it would be nice to have a preprocessor/parse transform that converts the form

(foo:bar baz ..)

to

(: foo bar baz ...)

I find the former much more readable.

Yes, it is easier to read but as yet I don't have any infix operators, and : is just a normal symbol character so foo:bar is a normal symbol. I have so far tried to avoid making any characters but the bare minimum needed for sexps as "special", it keeps the parsing easier. It would be possible to fix this in the macro expander if enough people complain. :-)

I have not really planned to add an explicit parse transform operation as in vanilla Erlang as it is "so easy" (TM) to do it yourself.

- It would like to have an Erlang-style '=' operator for binding
instead of (let). The main difference is in the number of parentheses
and the scoping rules. So, instead of

(let ((a 1) (b 2)) (+ a b))

you could write

(= (a 1) (b 2))
(+ a b)

No, one thing I definitely want is variable scoping. I think that was a definite mistake in vanilla Erlang. 20/20 hindsight.

- String literals should be interpreted as literal lists rather than
sexps. It seems redundant to write a single quote before a string
literal.

The problem is that string literals are parsed into lists, strings don't exist. Seeing their is no abstract syntax I can't tag these as any different from other literal lists as is done in vanilla and the compiler/interpreter just sees lists. So they have to be quoted. I agree though that it is not beautiful. Perhaps all integers in the function position could just be a function which evaluates to a list of itself and all the arguments. I am probably joking.

- It would be great to have syntax for multi-line strings and binaries.

Same problem here with string literals within binaries. The syntax can be modified later when requests stabilise.

- Distributing LFE under a standard open source license would
encourage its adoption and foster community contributions.
lfe_scan.erl has this license notice:

%%% (C)Robert Virding. This stuff is mine, distributed without
%%% warranty "as is" and may not be used commercially without letting
%%% me know.

This wording is ambiguous. Is the only requirement to using LFE
commercially to let you know, or it it required to buy a license for
commercial use? What happens to user contributions? Etc.

That only applies to Leex and I know I have to do something with Leex. What I mean is that I am just interested in knowing who is using it and for what and have no intention of selling licenses, except of course if I find that it is wildly popular and I could make a fortune on it and retire to the south seas. I.e. no licenses, you can quote that.

As for LFE I am giving it away. If somebody has a nice, short license notice expressing this then let me know. I would, however, become disappointed if someone else started selling it. :-)

Regards,
Yariv

 Robert

Robert Virding

unread,
Mar 3, 2008, 4:40:51 PM3/3/08
to Richard Carlsson, Erlang Questions
Yes Richard I remember most of this from the bad old days. :-)

What I was getting at was that there is no really no way to return a true function pointer in the way that Scheme or CL can do. This is not a Core problem but an Erlang implementation property. Even if doing


let MyCons = 'cons'/2 in apply MyCons(A, B)

is legal in Core as is generally using name/arity as data then unless these are optimised away as you mentioned then a later pass in the compiler, v3_kernel, actually converts them to a fun. In the Erlang implementation you cannot directly reference functions as data.

I personally think that it was a Good Thing that name/arity function names were kept in Core as it is a (mis)feature of Erlang and trying to hide this would have led to strangeness. That is why I have kept in the distinction in LFE and may even make it more noticeable. I am not yet decided either way.

Anyway letrec in LFE maps directly to letrec in Core, which works on name/arity function names, so the following LFE code is perfectly legal and works as expected:

  (letrec ((f (lambda (x) (+ x n)))
       (f (lambda (x y) (+ x (+ y n)))))
    (list (f n) (f n 10)))

Though it might be hard explaining to people that it is legal. :-) At least until they see it as Erlang and not as lisp. I don't really want to try and hide properties of the underlying implementation, especially when you can't really avoid seeing them. I mean I can define functions with the same name with different arities so I will never be able to refer to a function by just its name.

The Core Erlang spec, together with the record definitions, were a great help in generating code. That together with writing Erlang code and seeing what it resulted in.

Robert

Torbjorn Tornkvist

unread,
Mar 3, 2008, 3:48:49 PM3/3/08
to erlang-q...@erlang.org
Robert Virding wrote:
>
> As for LFE I am giving it away. If somebody has a nice, short license
> notice expressing this then let me know. I would, however, become
> disappointed if someone else started selling it. :-)

Then why not simply put it at code.google.com with a GPL license
attached to it?

--Tobbe

Lev Walkin

unread,
Mar 3, 2008, 9:20:32 PM3/3/08
to Torbjorn Tornkvist, erlang-q...@erlang.org
Torbjorn Tornkvist wrote:
> Robert Virding wrote:
>> As for LFE I am giving it away. If somebody has a nice, short license
>> notice expressing this then let me know. I would, however, become
>> disappointed if someone else started selling it. :-)
>
> Then why not simply put it at code.google.com with a GPL license
> attached to it?

BSD license is much shorter and nicer :)

--
vlm

Benjamin Tolputt

unread,
Mar 3, 2008, 10:24:38 PM3/3/08
to Lev Walkin, erlang-q...@erlang.org, Torbjorn Tornkvist
I usually stay out of the licensing flame-wars, and hoepfully this won't
result in one. I agree that BSD, MIT, or even Apache are better licenses
than GPL "for the stated purpose" (which as I understand it is simply to
prevent people taking credit for the work, though Robert can correct me
if I am wrong here).

If LFE were made GPL, it essentially makes any distribution of Erlang
using it GPL. The wxWidgets license (basically LGPL with static linkage
exception) is a better fit, if GPL is a must, given that you only need
to distribute the source of the library (i.e. LFE) and not the
applications linked to & depending on it.

Regards,
B.J.Tolputt

Lev Walkin wrote:
> Torbjorn Tornkvist wrote:
>
>> Robert Virding wrote:
>>
>>> As for LFE I am giving it away. If somebody has a nice, short license
>>> notice expressing this then let me know. I would, however, become
>>> disappointed if someone else started selling it. :-)
>>>
>> Then why not simply put it at code.google.com with a GPL license
>> attached to it?
>>
>
> BSD license is much shorter and nicer :)
>
>

_______________________________________________

Robert Virding

unread,
Mar 4, 2008, 6:28:04 PM3/4/08
to Benjamin Tolputt, erlang-q...@erlang.org, Torbjorn Tornkvist
On 04/03/2008, Benjamin Tolputt <b...@pmp.com.au> wrote:
I usually stay out of the licensing flame-wars, and hoepfully this won't
result in one. I agree that BSD, MIT, or even Apache are better licenses
than GPL "for the stated purpose" (which as I understand it is simply to
prevent people taking credit for the work, though Robert can correct me
if I am wrong here).

I am a great fan of the KISS principle, so in this case shorter is definitely better. You understood me correctly in this case I just want credit for my work. At the moment there's no rush anyway, if someone were to "steal" it I would just rewrite a better one. :-)

Robert

Yariv Sadan

unread,
Mar 6, 2008, 2:58:43 AM3/6/08
to Robert Virding, Erlang Questions
Hi, I think I found a bug in lfe_eval.

I created the following macro:

(define-syntax bar
(macro
((vals)
(: lists map (lambda (x) (: io format '"~p~n" x)) vals) ())))

and the following function:

(define (foo)
(bar (1 2 3)))

When I call '(foo)' I get the following error:

** exception error: lfe_eval:'-eval_lambda/2-fun-0-'/2 called with one argument
in function lists:map/2
in call from lfe_eval:eval_body/2
in call from lfe_macro:macro/3
in call from lfe_macro:expand_tail/3
in call from lfe_macro:expand/2
in call from lfe_macro:expand_top_forms/2
in call from lfe_macro:expand_top_forms/2
in call from lfe_macro:expand_file/2

Also, can you please explain the difference between 'macro' and
'syntax-rules'? 'macro' seems to do what I expect and I'm not sure
when syntax-rules would be a better option.

Thanks,
Yariv

2008/3/1 Robert Virding <rvir...@gmail.com>:

Robert Virding

unread,
Mar 6, 2008, 4:39:43 PM3/6/08
to Yariv Sadan, Erlang Questions
On 06/03/2008, Yariv Sadan <yariv...@gmail.com> wrote:
Hi, I think I found a bug in lfe_eval.

I created the following macro:

(define-syntax bar
  (macro
   ((vals)
    (: lists map (lambda (x) (: io format '"~p~n" x)) vals) ())))

and the following function:

(define (foo)
  (bar (1 2 3)))

When I call '(foo)' I get the following error:

** exception error: lfe_eval:'-eval_lambda/2-fun-0-'/2 called with one argument
     in function  lists:map/2
     in call from lfe_eval:eval_body/2
     in call from lfe_macro:macro/3
     in call from lfe_macro:expand_tail/3
     in call from lfe_macro:expand/2
     in call from lfe_macro:expand_top_forms/2
     in call from lfe_macro:expand_top_forms/2
     in call from lfe_macro:expand_file/2

That's a  bug, but it has now been fixed. I have released a patch on trapexit.org with a fix and a few other goodies.

Also, can you please explain the difference between 'macro' and
'syntax-rules'? 'macro' seems to do what I expect and I'm not sure
when syntax-rules would be a better option.

'syntax-rules' are simpler and are taken from Scheme. Each rule consists of (pattern expansion) where pattern is matched against the arguments of the macro call and the values of the variables from pattern are substituted into the expansion which is then returned. It is like a simple form of backquote macro where the only possible unquoting is symbol names. You can't "do" anything in the pattern except return it. So for example a simple recursive definition of let* (sequential let) would be:

(define-syntax let*
  (syntax-rules
    ([(vb . vbs) . b] [let (vb) (let* vbs . b)])
    ([() . b] [begin . b])))

Here I also use [...] as alternative to (...) to mark out the patterns and the expansion.

Syntax-rules are useful when the macro can be written as a simple expansion, although there is not much difference in using macro with a simple backquote. See test_macro.lfe for an example of the same macro written in both ways. Macro needs the evaluator to evaluate the body while syntax-rules does not.

I am thinking of changing the names to defsyntax and defmacro :

(defsyntax let*
  (pat1 exp1)
  ... )

(defmacro let*
  (pat1 . body1)
  ... )

What does the "user community" feel about that? Having both under one define-syntax maybe a clearer way to express the intention though.

Thanks,

Yariv

Robert

Robert Virding

unread,
Mar 6, 2008, 4:43:09 PM3/6/08
to Erlang Questions
First patch to LFE 0.1 has been added to trapexit.org, http://forum.trapexit.org/viewtopic.php?p=40619#40619. Apart from fixing the bug it also has:

- Macro expansion now occurs in patterns
- _ added as don't care variable to patterns

as well as some internal code changes.

Just unload it on top of the original files and recompile.

Robert

karol skocik

unread,
Mar 6, 2008, 6:21:52 PM3/6/08
to erlang-q...@erlang.org
Yes, defsyntax & defmacro are definitely nicer. Also, 'begin' (progn)
could be replaced with 'do', and other macros l
do1/do2 (CL's progn1/progn2) would be nice. They are trivial with
macros, having them built-in is about preventing dozens of
'common-utils' modules floating around doing the same basic stuff...

Karol

> I am thinking of changing the names to defsyntax and defmacro :
>
> (defsyntax let*
> (pat1 exp1)
> ... )
>
> (defmacro let*
> (pat1 . body1)
> ... )
>
> What does the "user community" feel about that? Having both under one
> define-syntax maybe a clearer way to express the intention though.

> Robert

Torbjorn Tornkvist

unread,
Mar 10, 2008, 5:11:48 PM3/10/08
to erlang-q...@erlang.org

Perhaps a stupid question. Do LFE implement currying?
If not, why?

I want currying... :-)

--Tobbe

> trapexit.org <http://trapexit.org>,
> http://forum.trapexit.org/viewtopic.php?p=40268#40268.

Robert Virding

unread,
Mar 10, 2008, 6:30:26 PM3/10/08
to Torbjorn Tornkvist, erlang-q...@erlang.org
On 10/03/2008, Torbjorn Tornkvist <to...@tornkvist.org> wrote:

Perhaps a stupid question. Do LFE implement currying?
If not, why?

I want currying... :-)

--Tobbe

Nope, not until it is supported in the VM and by the language*. Write some macros for it.

Robert

* I personally think that the way Erlang is defined today will always make currying in Erlang a bit of a hack, and a rather risky hack at that.

Kevin Scaldeferri

unread,
Mar 10, 2008, 6:44:30 PM3/10/08
to Torbjorn Tornkvist, erlang-q...@erlang.org

On Mar 10, 2008, at 2:11 PM, Torbjorn Tornkvist wrote:

>
> Perhaps a stupid question. Do LFE implement currying?
> If not, why?
>
> I want currying... :-)
>

Here's something I threw together in a couple minutes:

%% F({a,b}) -> F'(a,b)
curry(F, Arity) ->
if
Arity =:= 1 -> fun(A) -> F({A}) end;
Arity =:= 2 -> fun(A,B) -> F({A,B}) end;
Arity =:= 3 -> fun(A,B,C) -> F({A,B,C}) end;
Arity =:= 4 -> fun(A,B,C,D) -> F({A,B,C,D}) end;
Arity =:= 5 -> fun(A,B,C,D,E) -> F({A,B,C,D,E}) end;
true -> throw(unsupported_arity)
end.

%% F(a,b) -> F'({a,b})
uncurry(F) ->
fun(Tuple) -> apply(F, tuple_to_list(Tuple)) end.


A gross hack, to be sure, although I can't see how you could have any
hope to avoid having to specify an Arity to curry(). Maybe there's a
way to implement it less horribly, though.

BTW, did you actually mean that you want partial application? Via a
similar process:

papply(F, Arity, Arg) ->
if
Arity =:= 1 -> fun() -> F(Arg) end;
Arity =:= 2 -> fun(A) -> F(Arg,A) end;
Arity =:= 3 -> fun(A,B) -> F(Arg,A,B) end;
Arity =:= 4 -> fun(A,B,C) -> F(Arg,A,B,C) end;
Arity =:= 5 -> fun(A,B,C,D) -> F(Arg,A,B,C,D) end;
true -> throw(unsupported_arity)
end.


-kevin

Kevin Scaldeferri

unread,
Mar 10, 2008, 7:25:51 PM3/10/08
to Kevin Scaldeferri, erlang-q...@erlang.org, Torbjorn Tornkvist

On Mar 10, 2008, at 3:44 PM, Kevin Scaldeferri wrote:

>
> On Mar 10, 2008, at 2:11 PM, Torbjorn Tornkvist wrote:
>
>>
>> Perhaps a stupid question. Do LFE implement currying?
>> If not, why?
>>
>> I want currying... :-)
>>
>
> Here's something I threw together in a couple minutes:
>
> %% F({a,b}) -> F'(a,b)
> curry(F, Arity) ->
> if
> Arity =:= 1 -> fun(A) -> F({A}) end;
> Arity =:= 2 -> fun(A,B) -> F({A,B}) end;
> Arity =:= 3 -> fun(A,B,C) -> F({A,B,C}) end;
> Arity =:= 4 -> fun(A,B,C,D) -> F({A,B,C,D}) end;
> Arity =:= 5 -> fun(A,B,C,D,E) -> F({A,B,C,D,E}) end;
> true -> throw(unsupported_arity)
> end.
>

Should do slightly more browsing of the docs before posting :-). This
is a slight improvement:

%% F({a,b}) -> F'(a,b)

curry(F) ->
{arity, Arity} = erlang:fun_info(F, arity),


if
Arity =:= 1 -> fun(A) -> F({A}) end;
Arity =:= 2 -> fun(A,B) -> F({A,B}) end;
Arity =:= 3 -> fun(A,B,C) -> F({A,B,C}) end;
Arity =:= 4 -> fun(A,B,C,D) -> F({A,B,C,D}) end;
Arity =:= 5 -> fun(A,B,C,D,E) -> F({A,B,C,D,E}) end;
true -> throw(unsupported_arity)
end.

_______________________________________________

Hynek Vychodil

unread,
Mar 11, 2008, 2:32:55 AM3/11/08
to Kevin Scaldeferri, erlang-q...@erlang.org, Torbjorn Tornkvist

That's wrong I think. Function F will be always called with arity 1.


_______________________________________________
erlang-questions mailing list
erlang-q...@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions



--
--Hynek (Pichi) Vychodil

Kevin Scaldeferri

unread,
Mar 11, 2008, 3:17:03 AM3/11/08
to Hynek Vychodil, erlang-q...@erlang.org, Torbjorn Tornkvist


Yup, I realized that later as well. That change works for papply, but
not for curry. (This shortcoming is not restricted to Erlang, one
should note. For example, in Haskell, curry and uncurry only operate
on binary functions.)


-kevin

Torbjorn Tornkvist

unread,
Mar 11, 2008, 4:04:54 AM3/11/08
to erlang-q...@erlang.org

Well, the notion that M:F/Arity is unique doesn't need to hold
if you're implementing your own language on top of Erlang core, or ?

As an example, look at my little Haskell-to-Erlang experiment:

http://blog.tornkvist.org/blog.yaws?id=1190846785574003

As you can see, it is also possible to make user-defined guards
when you're rolling your own language on top of Erlang core.

Cheers, Tobbe

Mats Cronqvist

unread,
Mar 11, 2008, 4:31:38 AM3/11/08
to Kevin Scaldeferri, erlang-q...@erlang.org, Torbjorn Tornkvist
Kevin Scaldeferri wrote:
> On Mar 10, 2008, at 11:32 PM, Hynek Vychodil wrote:
>
>
>> On Tue, Mar 11, 2008 at 12:25 AM, Kevin Scaldeferri <ke...@scaldeferri.com
>>
>>> wrote:
>>>
>> On Mar 10, 2008, at 3:44 PM, Kevin Scaldeferri wrote:
>>
>>
>>> On Mar 10, 2008, at 2:11 PM, Torbjorn Tornkvist wrote:
>>>
>>>
>>>> Perhaps a stupid question. Do LFE implement currying?
>>>> If not, why?
>>>>
>>>> I want currying... :-)
>>>>
>>>>
>>> Here's something I threw together in a couple minutes:
>>>
>>> %% F({a,b}) -> F'(a,b)
>>> curry(F, Arity) ->
>>> if
>>> Arity =:= 1 -> fun(A) -> F({A}) end;
>>> Arity =:= 2 -> fun(A,B) -> F({A,B}) end;
>>> Arity =:= 3 -> fun(A,B,C) -> F({A,B,C}) end;
>>> Arity =:= 4 -> fun(A,B,C,D) -> F({A,B,C,D}) end;
>>> Arity =:= 5 -> fun(A,B,C,D,E) -> F({A,B,C,D,E}) end;
>>> true -> throw(unsupported_arity)
>>> end.
>>>
>>>
IANACS(*), but i thought currying was supposed to look like this;

curry(F,Arg) ->
case erlang:fun_info(F,arity) of
{_,1} -> fun() -> F(Arg) end;
{_,2} -> fun(A) -> F(A,Arg) end;
{_,3} -> fun(A,B) -> F(A,B,Arg) end;
{_,4} -> fun(A,B,C) -> F(A,B,C,Arg) end
end.

mats

(*) I Am Not A Computer Scientist

mats_cronqvist.vcf

Kevin Scaldeferri

unread,
Mar 11, 2008, 6:41:34 PM3/11/08
to Erlang mailing list
somehow this branch of the conversation went off-list. Bringing it
back as others might be interested.


-kevin


On Mar 11, 2008, at 2:49 PM, Mats Cronqvist wrote:

> Kevin Scaldeferri wrote:

>>>> No, that's partial application. Or, sort of reverse partial
>>>> application. Compare to the papply function I wrote.
>>>>
>>>>
>>>> -kevin
>>>
>>> like i said, i really have no idea what i'm talking about. but i
>>> found several descriptions like this;
>>>
>>> http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52549
>>>
>>> "In functional programming, currying is a way to bind arguments with
>>> a function and wait for the rest of the arguments to show up later.
>>> You "curry in" the first few parameters to a function, giving
>>> you a function that takes subsequent parameters as input and
>>> calls the original with all of those parameters."
>>>
>>> i'm so confused...
>>
>> So is the author of that paragraph :-). Here's a better
>> explanation from wikipedia: http://en.wikipedia.org/wiki/Currying
>>
>> "Given a function f of type f : (X x Y) -> Z , then currying it
>> makes a function curry(f) : X -> (Y -> Z) . That is, curry(f) takes
>> an argument of type X and returns a function of type Y -> Z . "
>>
>> So, what you see here is that in some sense currying is a precursor
>> to partial application.
>
> i guess you just can't trust random web pages these days... i found
> a better source of info on the haskell web (surprise!)
>
>> Part of the confusion in talking about this is that this is all in
>> the context of theories of computation where all functions are
>> unary (like the lambda calculus). In languages with arbitrary
>> arity of functions, it's a little less clear what currying means.
>> I made the choice to interpret it as converting a unary function
>> expecting a tuple into a multi-ary function. You could argue,
>> though, that maybe it should be this instead:
>>
>> curry(F) when is_function(F,2)->
>> fun(X) ->
>> fun(Y) -> F(X,Y) end
>> end.
>>
>>
>> Notice, though, that curry() doesn't actually apply any arguments,
>> it just returns a function which naturally allows partial
>> application.
>
> i see... thanks a lot for your time!
>
>>
>> -kevin
>>
>> P.S. Did you intentionally only send this to me? I think there's
>> frequent confusion about this, so it seems to be like valuable
>> discussion for the list
>>
> i did "reply all" in my trusty old thunderbird; i think your
> previous mail was sent to me only (at least it looked like that to
> thunderbird). feel free to forward any/all of this to the list. i'm
> pretty sure i'm not the only one confused by this (though i might be
> the only one that cares, of course.)
>
> mats
> <mats_cronqvist.vcf>

Vlad Balin

unread,
Mar 11, 2008, 7:24:49 PM3/11/08
to Torbjorn Tornkvist, erlang-q...@erlang.org
> Perhaps a stupid question. Do LFE implement currying?
> If not, why?
>
> I want currying... :-)
Not a big deal.

your_curried_func( A ) -> fun( B, C ) -> your_curried_func( A, B, C ) end.
your_curried_func( A, B ) -> fun( C ) -> your_curried_func( A, B, C ) end.
your_curried_func( A, B, C ) -> ...

One extra line for each curring case. For me it's completely ok, but
you can define macro to hide this stuff if it bothers you. You'll get
something like this:

?curried_3( your_curried_func )
your_curried_func( A, B, C ) -> ...

Richard A. O'Keefe

unread,
Mar 12, 2008, 12:35:44 AM3/12/08
to Erlang mailing list
Can we distinguish, please, between
partial application
and
currying?
Neither of them is a special case of the other.

Currying is the act of taking a function of multiple arguments and,
without binding any, returning a function that takes them one at a time.
For example,

curry(F) ->
case erlang:fun_info(F, arity)
of 0 -> fun (_) -> F() end
; 1 -> F
; 2 -> fun (X1) -> fun (X2) -> F(X1,X2) end end
; 3 -> fun (X1) -> fun (X2) -> fun (X3) -> F(X1,X2,X3) end end
end
% continue as long as you have patience or use
end.

Partial application is the act of taking a function of multiple
arguments and, by some means, supplying some but not all of them,
returning a function, not necessarily unary, awaiting the rest.

The British AI language Pop-2 supported partial application but not
currying. If I remember correctly, f(% ... %) provided *trailing*
arguments for f, leaving it still awaiting its leading arguments.
With a curried function, it is easiest to provide leading arguments,
but it is often useful to supply others.

For example, in Haskell a binary operator like > is curried:
> :: Ord a => a -> a -> Bool
We might want to supply *either* of the arguments:

x_exceeds = (x >)
returns \y -> x > y

exceeding_x = (> x)
returns \y -> y > x

Working on binary functions, we might have

apply_left(X, Op) -> fun (Y) -> Op(X, Y) end.

apply_right(Op, Y) -> fun (X) -> Op(X, Y) end.

Reply all
Reply to author
Forward
0 new messages