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