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

Sean Hinde <>
Fri Aug 25 12:28:16 CEST 2006


This is fun!

Here is my Erlang translation of the GPS from Norvig, following the  
lisp code as closely as possible.

I found it quite kludgy to write in erlang. I ended up using a  
deprecated function from lists.erl, and there were some features of  
lisp like named parameters and extension parameters that seemed quite  
nice - although perhaps not so much until Luke forcefully pointed out  
the benefits :-)

Heavy higher order function programming certainly seems less elegant  
in Erlang than lisp or any of the modern statically typed functional  
languages.

Sean

-module(gps).

-export([gps/3]).

-record(op,
         {
           action,
           preconds = [],
           add_list = [],
           del_list = []
          }).

gps(State, Goals, Ops) ->
     put(state, State),
     put(ops, Ops),
     lists:all(fun achieve/1, Goals).

achieve(Goal) ->
     State = get(state),
     Ops = get(ops),
     lists:member(Goal, State) orelse
         lists:any(fun apply_op/1, find_all(Goal, Ops, fun  
appropriate_p/2)).

appropriate_p(Op, Goal) ->
     lists:member(Goal, Op#op.add_list).

apply_op(Op) ->
     case lists:all(fun achieve/1, Op#op.preconds) of
         true ->
             io:format("Executing ~p~n",[Op#op.action]),
             put(state, get(state) -- Op#op.del_list),
             put(state, merge(get(state), Op#op.add_list)),
             true;
         false ->
             false
     end.

merge(L1, L2) ->
     lists:merge(lists:sort(L1), lists:sort(L2)).

find_all(Goal, Ops, Pred) ->
     lists:filter(Pred, [Goal], Ops).



On 25 Aug 2006, at 03:05, Jay Nelson wrote:

> 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