Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I return a list in Prolog?

Tags:

list

prolog

Let's say I have these facts:

parent(bob, sam). %bob is sam's parent
parent(sara, sam). %sara is sam's parent

I wanted to find out who were sam's parents and return them in a list and as such used:

list_parents(P, L) :- findall(Parent, parent(Parent, P), L).

What I want to do now is ask the same question but with only one argument as such:

findParents(sam).

I tried:

findParents(Name) :- list_parents(Name, L).

but this way Prolog simply answers "True".

like image 344
porlognewbie Avatar asked May 26 '11 17:05

porlognewbie


People also ask

How do I display a list in Prolog?

In Prolog list elements are enclosed by brackets and separated by commas. Another way to represent a list is to use the head/tail notation [H|T]. Here the head of the list, H, is separated from the tail of the list, T, by a vertical bar. The tail of a list is the original list with its first element removed.

How do you create a list in Prolog?

If you want to create a list of consecutive numbers from 1 to N you can use builtin predicates findall/3 and between/3 this way: do_list(N, L):- findall(Num, between(1, N, Num), L). ?- do_list(5,L). L = [1, 2, 3, 4, 5].

What is a list in Prolog?

A list is an ordered sequence of elements that can have any length. Lists are a common data structure in computer programming. In Prolog, lists are represented as a tree consisting of structures that have no arguments, an empty list, or two arguments: a head and a tail.

What does \+ mean in Prolog?

\+ = 'if unsure or false , assume false '


3 Answers

The thing with prolog is that it's a little different than most languages (understatement, if there every was one):

  • All variables are locally scoped.

  • Variable values are invariant once bound (unified), unless backtracking unbinds it.

  • Predicates do not return a value in the conventional sense. They either succeed or fail.

  • To get value back from testing a predicate, you evaluate the predicate passing it something from your predicate. It doesn't matter if you pass it a variable or a bound value: the called predicate will succeed or value if what the caller has unifies with what you passed it. If you passed a variable, and the called predicate unifies it with a non-variable value, your variable is bound to that value. Think of it (somewhat) as if you had a procedural language where every function returned bool and all parameter values were passed by reference.

What you tried worked:

findParents(Name) :- list_parents(Name, L).

The variable L was unified with (was bound to) the list returned by findall/3. And then it went out of scope.

If you want to actually do something with that returned (bound) value, you need to deal with it where it's in-scope, or unify that value with something that that predicate was invoked with and thus pass it up the call stack. Or, you could assert it into the database of facts and save it for later.

The way prolog works is that the root predicate used to start your "program" defines a search tree in terms of the predicates in your database. Prolog's "engine" then performs a depth-first, left-to-right search of that tree. Your predicate succeeds when the engine gets to a leaf node of the search tree you defined. Backtracking into your predicate causes the engine to look for the next solution in the search tree.

As a result, anything you want to accomplish in a persistent way has to occur as a side effect of the prolog "engine" evaluating a predicate. For instance print() always succeeds just once (when you enter the box)...and as a side effect prints whatever you asked it to print. Backtracking into the print doesn't "undo" the print, but print() doesn't succeed again.

like image 173
Nicholas Carey Avatar answered Oct 19 '22 03:10

Nicholas Carey


The func library provides a syntax for functions with return values in SWI-Prolog. In this example, you can print all parents of sam by writing writeln(list_parents $ sam):

:- initialization(main).
:- use_module(library(func)).

main :- writeln(list_parents $ sam).

list_parents(P, L) :- findall(Parent, parent(Parent, P), L).
parent(bob, sam). %bob is sam's parent
parent(sara, sam). %sara is sam's parent

Similarly, you can define a function with multiple parameters like this one:

% return a item at an index in a list.
nth0((Index,List),ToReturn) :-
    nth0(Index,List,ToReturn).

...and then use it like this:

example :-
    ListIndex = (nth0 $(0,[1,2,3,4])), %returns 1, which is the first item in this list
    writeln(ListIndex).
like image 3
Anderson Green Avatar answered Oct 19 '22 03:10

Anderson Green


you could print the list if want only the user to see it something like:

findParents(Name):-
   list_parents(Name,L),
   print(L).

but this isnt exactly returning. remember, in prolog, there are no functions and therefore no "return values". you can simulate a function by writing foo(Args,Return) but you can always call it like foo(X,sam) -sometimes it will give what you want, sometimes it wont, sometimes it will crash.

like image 2
Thanos Tintinidis Avatar answered Oct 19 '22 04:10

Thanos Tintinidis