Erlang (programming language)/Tutorials/List Comprehensions: Difference between revisions

From Citizendium
Jump to navigation Jump to search
imported>Eric Evers
imported>Eric Evers
Line 10: Line 10:


Note: in general using huge numbers of atoms is not a good idea.
Note: in general using huge numbers of atoms is not a good idea.
 
%======================================================================
  -module(think).              %
  -module(think).              %
  -compile(export_all).        %
  -compile(export_all).        %
Line 30: Line 30:
  parent(noah,shem) -> true;
  parent(noah,shem) -> true;
  parent(_X,_Y) -> false.
  parent(_X,_Y) -> false.
                                                %
%
people() -> [ adam, shem, cain, abel, eve, noah ].
%
father_of() -> [ {X,Y} || X <- people(), Y <- people(), parent(X,Y), male(X) ].
mother_of() -> [ {X,Y} || X <- people(), Y <- people(), parent(X,Y), female(X) ].
%============================================================================
compile with c(think). and generate output with:
17> think:father_of() ++ think:mother_of().
[{adam,cain},{adam,abel},{noah,shem},{eve,cain},{eve,abel}]
%============================================================================
 
The above program is terse and logical. Unfortunately, the traditional predicate
ancestor(X) is not included in module think.erl because it is a recursive predicate
and can not be programmed simply.
 
In the program below we include the recursive predicate ancestor(), for
completeness.
 
%=============================================================================
 
-module(family).
-compile(export_all).
 
  people() ->
  people() ->
        [ adam, shem, cain, abel, eve, noah ].
    [amy,
                                                %
    mark, maya,  
  father_of() ->
    joe,  
        [ {X,Y} || X <- people(), Y <- people(), parent(X,Y), male(X) ].
    fred,  
  mother_of() ->
    alice].
         [ {X,Y} || X <- people(), Y <- people(), parent(X,Y), female(X) ].
 
  parent(amy, mark) -> true;
parent(maya, joe) -> true;
parent(mark, joe) -> true;
parent(joe, fred) -> true;
parent(fred, alice) -> true;
parent(_,_) -> false.
 
male(fred) -> true;
male(joe) -> true;
male(mark) -> true;
male(_) -> false.
% calc_parent() might be empty
  calc_parent(Child) ->  
         _P = [Parent || Parent <- people(), parent(Parent,Child)].  


compile with c(think). and generate output with:
% ancestor predicate is recursive and returns true or false
  17> think:father_of() ++ think:mother_of().
ancestor(A, C) -> 
  [{adam,cain},{adam,abel},{noah,shem},{eve,cain},{eve,abel}]
        Is_Parent = parent(A, C),
        if
                Is_Parent == true ->
                      true;
                true ->
                        P = calc_parent(C),
                        if
                                P == [] ->
                                        false;
                                length(P) == 1 ->
                                        ancestor(A, hd(P));   
                                        % has only one parent
                                true ->
                                        ancestor(A, hd(tl(P))) or ancestor(A, hd(P)
                                        % has more than one parent
                end
        end.
 
% find all {ancestor, descendend} pairs where their genders match
 
start() ->
        Question = ["who is an ancestor and the same gender?"],
        Answer = [{A,B} || A <- people(), B <- people(), ancestor(A,B),
                male(A)==male(B)],
        {Question, Answer}.
%===========================================================================
% Sample output --------------------
  % 1> family:start().
  % [{amy,alice},{maya,alice},{mark,joe},{mark,fred},{joe,fred}]
%===========================================================================

Revision as of 20:09, 17 May 2009

Intermediate list comprehensions

An important use of List Comprehensions is to help translate prolog into erlang.

1- Erlang is a functional language designed for message passing (MIMD) parallel processing. Prolog is designed for logic programming. Sometimes a problem is most easily defined as a logical set of constraints on some set of data. If one thinks logically or thinks in constraints, or thinks in prolog, this style of list comprehensions can be a helpful way to do your tasks in erlang. There exist many useful solutions in prolog that can be moved to erlang via list comprehensions.

2- Constraint programming and logic programming are considered a higher level way to program then functions, and hence, are a good way to save you time and increase terseness.

Warning: constraint and logic based programs can be harder to debug because strict step by step actions are hidden and delegated to the list comprehension engine. Order of constraints in erlang list comprehensions can affect the output. Order dependence of constraints can be a non-intuitive distraction.

Note: in general using huge numbers of atoms is not a good idea.

%======================================================================
-module(think).              %
-compile(export_all).        %
                             %
male(adam) -> true;          %
male(seth) -> true;
male(cain) -> true;
male(abel) -> true;
male(noah) -> true;
male(_X) -> false.
                             %
female(eve) -> true;
female(_X) -> false.
                             %
parent(adam,cain) -> true;
parent(adam,abel) -> true;
parent(eve,cain) -> true;
parent(eve,abel) -> true;
parent(noah,shem) -> true;
parent(_X,_Y) -> false.
%
people() -> [ adam, shem, cain, abel, eve, noah ].
%
father_of() -> [ {X,Y} || X <- people(), Y <- people(), parent(X,Y), male(X) ].
mother_of() -> [ {X,Y} || X <- people(), Y <- people(), parent(X,Y), female(X) ].
%============================================================================
compile with c(think). and generate output with: 
17> think:father_of() ++ think:mother_of().
[{adam,cain},{adam,abel},{noah,shem},{eve,cain},{eve,abel}]
%============================================================================

The above program is terse and logical. Unfortunately, the traditional predicate ancestor(X) is not included in module think.erl because it is a recursive predicate and can not be programmed simply.

In the program below we include the recursive predicate ancestor(), for completeness.

%=============================================================================
-module(family).
-compile(export_all).
people() ->
    [amy,
    mark, maya, 
    joe, 
    fred, 
    alice].
parent(amy, mark) -> true;
parent(maya, joe) -> true;
parent(mark, joe) -> true;
parent(joe, fred) -> true;
parent(fred, alice) -> true;
parent(_,_) -> false.
male(fred) -> true;
male(joe) -> true;
male(mark) -> true;
male(_) -> false.
% calc_parent() might be empty
calc_parent(Child) ->    
       _P = [Parent || Parent <- people(), parent(Parent,Child)].   
% ancestor predicate is recursive and returns true or false
ancestor(A, C) ->  
       Is_Parent = parent(A, C),
       if
               Is_Parent == true ->
                      true;
               true -> 
                       P = calc_parent(C),					
                       if
                               P == [] -> 
                                       false;
                               length(P) == 1 ->
                                       ancestor(A, hd(P));    
                                       % has only one parent
                               true ->
                                       ancestor(A, hd(tl(P))) or ancestor(A, hd(P))  
                                       % has more than one parent
                end
       end.
% find all {ancestor, descendend} pairs where their genders match
start() -> 
       Question = ["who is an ancestor and the same gender?"],
       Answer = [{A,B} || A <- people(), B <- people(), ancestor(A,B), 
                male(A)==male(B)],
       {Question, Answer}.
%===========================================================================
% Sample output --------------------
% 1> family:start().
% [{amy,alice},{maya,alice},{mark,joe},{mark,fred},{joe,fred}]
%===========================================================================