Lisp-Python vs. Erlang (was MLvtA, was Meta)
Bjorn Gustavsson
bjorn@REDACTED
Fri Aug 25 14:12:59 CEST 2006
I find it convenient to import functions from the lists module,
rather than writing "lists:" before every call.
I learned that practice from Robert Virding.
/Bjorn
Sean Hinde <sean.hinde@REDACTED> writes:
> 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
>
--
Björn Gustavsson, Erlang/OTP, Ericsson AB
More information about the erlang-questions
mailing list