Lisp-Python vs. Erlang (was MLvtA, was Meta)
Sean Hinde
sean.hinde@REDACTED
Fri Aug 25 15:31:17 CEST 2006
The "join with sort every time" was simply a convenient and simple
way to move past that point and into the meat of the problem.
Here is a test function:
test() ->
State = [son_at_home, car_needs_battery, have_money,
have_phone_book],
Goals = [son_at_school],
Ops = [#op{action = drive_son_to_school,
preconds = [son_at_home, car_works],
add_list = [son_at_school],
del_list = [son_at_home]},
#op{action = shop_installs_battery,
preconds = [car_needs_battery, shop_knows_problem,
shop_has_money],
add_list = [car_works]},
#op{action = tell_shop_problem,
preconds = [in_communication_with_shop],
add_list = [shop_knows_problem]},
#op{action = telephone_shop,
preconds = [know_phone_number],
add_list = [in_communication_with_shop]},
#op{action = look_up_number,
preconds = [have_phone_book],
add_list = [know_phone_number]},
#op{action = give_shop_money,
preconds = [have_money],
add_list = [shop_has_money],
del_list = [have_money]}
],
gps(State, Goals, Ops).
One small challenge could be to make a version using lists:filter/2
instead of the deprecated lists:filter/3
Sean
On 25 Aug 2006, at 13:22, Ulf Wiger ((TN/EAB)) wrote:
>
> 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