emir hkima
emir hkima

Reputation: 1

How to use Prolog's foreach/2 loop

I am trying to get the foreach/2 loop to work in Prolog (using tkeclipse). I understand it needs an element in the first argument and a list to search for that element within as a second argument.

My problem is that I haven't been able to make it work despite trying to rewrite my code and looking for solutions online.

In the following code, I try to write a predicate visite/2 that takes a list of museums and returns a list of cities where they are located.

Your help would be really appreciated as it would allow me to be better prepared for my upcoming exam.

musee(paris,louvre).
musee(rome,vatican).
musee(madrid,prado).
musee(berlin,kulturforum).
musee(londres,british_museum).

visite([X],L) :-
  findall(V,musee(V,_),List),
  (
    foreach(X,List) do findall(C,musee(C,X),L)
  ).

Upvotes: 0

Views: 169

Answers (2)

jschimpf
jschimpf

Reputation: 5034

ECLiPSe's do-loops are a shorthand for writing iterative recursions in a concise way. A simple application to your example would be

visite(Ms, Cs) :-
    ( foreach(M,Ms), foreach(C,Cs) do
        musee(C, M)
    ).

which is (modulo nondeterminism) equivalent to the explicit recursive form

visite([], []).
visite([M|Ms], [C|Cs]) :-
    musee(C, M),
    visite(Ms, Cs).

An algorithmically completely different way to solve your problem is using backtracking and findall, as in

visite(Ms, Cs) :-
    findall(C, (member(M, Ms), musee(C, M)), Cs).

Both are useful Prolog programming patterns.

Upvotes: 1

Nicholas Carey
Nicholas Carey

Reputation: 74277

This isn't Prolog (at least, not as I know it).

And if it were, the notion of an iterative loop is antithetic to Prolog.

Your problem statement:

I [am trying to write] a predicate visite/2 that takes a list of museums and returns a list of cities where they are located

could be better done in a way more idiomatic to Prolog. Something like this:

musee( paris   , louvre         ).
musee( rome    , vatican        ).
musee( madrid  , prado          ).
musee( berlin  , kulturforum    ).
musee( londres , british_museum ).

%
% Accepts a list of museums and returns the list of cities (villes) in which they are found.
% Or... vice versa.
% 
% We invoke a helper predicate that will prevent problems if/when the predicate
% is used in a generative manner.
visite( Ms,Vs ) :- visite( Ms, [], Vs ).

visite( []     , _ , []     ) .
visite( [M|Ms] , T , [V|Vs] ) :-
  musee(V,M) ,
  \+ member( M:V, T ),
  !,
  visite( Ms, [M:V|T], Vs )
  .


Upvotes: 0

Related Questions