Lisp-Python vs. Erlang (was MLvtA, was Meta)
Sean Hinde
sean.hinde@REDACTED
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