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

Ulf Wiger (TN/EAB) ulf.wiger@REDACTED
Fri Aug 25 14:22:49 CEST 2006


Not having though it through much, wouldn't 
ordsets be a better starting point than
unordered lists?

Ordsets are defined as being ordered lists, so it 
should be perfectly ok to use the odd lists library
function on them.

BR,
Ulf W 

> -----Original Message-----
> From: owner-erlang-questions@REDACTED 
> [mailto:owner-erlang-questions@REDACTED] On Behalf Of Sean Hinde
> Sent: den 25 augusti 2006 12:28
> To: Jay Nelson
> Cc: erlang-questions@REDACTED
> Subject: Re: Lisp-Python vs. Erlang (was MLvtA, was Meta)
> 
> 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