Lisp-Python vs. Erlang (was MLvtA, was Meta)

Jay Nelson jay@REDACTED
Fri Aug 25 04:05:59 CEST 2006


James Hague wrote:

 > But C# and Java aren't worth worrying about, IMO. The interesting
 > stuff is happening in the scripting language world, especially with
 > Python and Ruby. Those languages are a lot closer to Lisp
 > (see http://www.norvig.com/python-lisp.html).


Here's my conversion of the Lisp / Python example Norvig gave:

-------------------------------------------------

-module(norvig).

-export([generate/1, generate_tree/1]).

% Constructions...
grammar(s)   -> [np, vp];
grammar(np)  -> [art, n];
grammar(vp)  -> [v, np];

% Elements...
grammar(art) -> {"the", "a"};
grammar(n)   -> {"man", "ball", "woman", "table"};
grammar(v)   -> {"hit", "took", "saw", "liked"};

% Unknown.
grammar(_)   -> none.



generate(Phrase) when is_atom(Phrase) ->
   case grammar(Phrase) of
       none ->
           [Phrase];
       Words when is_tuple(Words) ->
           ChoiceNum = random:uniform(size(Words)),
           element(ChoiceNum, Words);
       Construct ->
           generate(Construct)
   end;

generate(Phrase) ->
   [generate(Word) || Word <- Phrase].



generate_tree(Phrase) when is_atom(Phrase) ->
   case grammar(Phrase) of
       none ->
           [Phrase];
       Words when is_tuple(Words) ->
           ChoiceNum = random:uniform(size(Words)),
           {Phrase, element(ChoiceNum, Words)};
       Construct ->
           [Phrase, generate_tree(Construct)]
   end;

generate_tree(Phrase) ->
   [generate_tree(Word) || Word <- Phrase].

---------------------------------------------------


I deliberately left it similar to his so that people unfamiliar with
lisp can see the correspondence, but I don't like the repetition
of the generate functions.  I would prefer to use a vlad-macro
or an annotate function to collapse the 2nd and 3rd branches
of the case statement so that there is a single generate function
in source code with two variants.

[This is an example of when a real macro is more readable than a
support function, because the two branches are different in
different ways, so the annotate function would have to have
two branches or there would have to be two annotate functions,
whereas a single macro could handle both cases.  As an exercise
to the reader, try writing the annotate approach and you'll see
the slight awkwardness.]


I think it reads clearer than lisp or python for the following reasons:

1) Prolog-like patterns map to the problem domain as a grammar function
     rather than the artificial list/hash map structure.  Also the compiler
     can optimize it more easily so clarity plus speed.

2) The list comprehension is just a succinct joy.

3) The use of tuples and lists differentiates intent better.

4) I prefer the case ... of ... end style over (cond ( ) ...) now.
     Syntactically there is not much difference but erlang
     suggests using similar (and more readable) patterns
     in each branch of the case.


If I had a month or two to burn I would go through the exercise
of porting Norvig's AI code to erlang.  There's no reason why
it wouldn't all work -- and possibly discover some new parallel
approaches in the process.  I think erlang is a perfectly suited
to many problems that lisp was.


jay



More information about the erlang-questions mailing list