tddd08 Tut1
tddd08 Tut1
. Read the lab instructions. Add module file (use module [init]add prog/sicstus). Modify your .emacs (see course page). Using the system Separate code (filename.pl) and query (*prolog*) buffers: all facts and rules in the file-buffer Just open or create filename.pl to enter prolog mode automatically. Save file and press C-c C-b to consult buffer and create the query window. Quit command: halt.. Strict deadline 17 Dec. for labs (if you miss it, you have to wait for the next re-examination) the labs should be completed, ie graded and reported in webreg that date so hand them in so I have time to grade them during the workday!
Prolog syntax
Variables: upper case first letter (X, Xs) Special ignored variables: _ as first letter Comments: % Single line comment
/* Block comment */
Facts
mother(anna, bob). anna is mother of bob. likes(_, icecream). Everybody likes icecream.
and Y is a parent of Z. sub-goals are separated by commas. And more, Lists, data structures. We'll get back to them later.
(written in *prolog* buffer) Queries can contain multiple simultanious subgoals separated by commas:
| ?- grandparent(X, jonatan), grandparent(X, skorpan). X = astrid
Prolog answers with either a satisfying binding, yes or no. If you want more answers, type ; and prolog will back-track and give another solution if it can find one.
Queries (goals)
| ?- mother(anna,bertil). yes | ?- parent(X,bertil). X = anna ? ; X = adam ? ; no | ?- grandfather(X,Y). X = adam, Y = cecilia ? ; X = arne, Y = christina ? ; no
Lists [X,2,c] is a (linked) list with three elements. [] is the empty list.
[X|Xs] is a list where the first element is X and the tail of the list is the list Xs. [1,2,3] is just syntactic sugar for [1|[2|[3|[]]]], which is the real
Lisp
() (1 2 3) (X . Xs)
Haskell
[] [1,2,3] (x:xs)
Queries
| ?- member(X, [1,2,3]). X = 1 ? ; X = 2 ? ; X = 3 ? ; no | ?- member(a, L). L = [a|_A] ? ;
Query
| ?- samelength(A,[1,2,3,4]). A = [_A,_B,_C,_D] ?
(=) != (=:=) != is
calculation (for example, 6 = 5 + 1 fails). We can do things like ?- X+1 = (7+Y)+Y. X = 7+1, Y = 1 Arithmetics X is E: Calculate expression E, then unify. X is 5+1 results in
X = 6; X is Y+Z requires that Y and Z are numbers (or
expressions containing numbers, for example Y = 2 * 3). E1 < E2, E1 =< E2, E1 >= E2, E1 > E2: Compare expressions. (Note that =< is used instead of <=) E1 =:= E2: Expressions E1 and E2 have the same value 2 * 3 = 3 * 2 false, 2 * 3 =:= 3 * 2 true.
Queries
| ?- fac(3, F). F = 6 ? yes | ?- fac(N, 6). {INSTANTIATION ERROR: _51>0 - arg 1}
Be careful when you use arithmetics, most predicates no longer work both ways!
Queries
| ?- ancestor1(X, cecilia). X = bertil ? ; X = anna ? ; X = adam ? ; no | ?- ancestor2(X, cecilia). X = bertil ? ; X = anna ? ; X = adam ? ; (*Infinite loop!*)
Example 6: Useful builtins length(L, N): L is a list with length N. setof(X, p(X), Set) Set (sorted list) of all results to query p(X). bagof(X, p(X), Bag) Bag of all results to query p(X). Example code:
| ?- setof(X, member(X, [b, a, c, a]), Set). Set = [a,b,c] ? yes
The bag contains all answers in the order they are found.
Negation
\+ p(X, Y): p(X, Y) has no solutions | ?- parent(anna, adam). no | ?- \+ parent(anna, adam). yes | ?- \+ parent(anna, X). no | ?- \+ parent(X, X). true ? ; yes \+ (X = Y) is written X \= Y: X, Y cannot be equal
In this case we get an infinite loop. number(X) only succeeds if X is instantiated to a number. In our case it is a variable. number does not generate numbers.
Debugging
search(X, X). search(tree(L, _R), X) :search(L, X). search(tree(_L, R), X) :search(R, X). | ?- trace. % The debugger will first creep -- showing everything (trace) yes % trace,source_info | ?- search(tree(tree(1, 2), tree(3, 4)), 3). 1 1 Call: search(tree(tree(1,2),tree(3,4)),3) ? 2 2 Call: search(tree(1,2),3) ? 3 3 Call: search(1,3) ? 3 3 Fail: search(1,3) ? 4 3 Call: search(2,3) ? 4 3 Fail: search(2,3) ? 2 2 Fail: search(tree(1,2),3) ? 5 2 Call: search(tree(3,4),3) ? 6 3 Call: search(3,3) ? 6 3 Exit: search(3,3) ? ? 5 2 Exit: search(tree(3,4),3) ? ? 1 1 Exit: search(tree(tree(1,2),tree(3,4)),3) ? yes % trace,source_info | ?-
Debugging, cont.
search(X, X). search(tree(L, _R), X) :search(L, X). search(tree(_L, R), X) :search(R, X).
Hints and remainders There are no return values! Using the result of a predicate is done by reusing variables:
do_something(Input, Output) :find_thing(Input, Thing), process(Thing, Output).
Not
do_something(Input) :Thing = find_things(Input), process(Thing) Prolog tries to interpret everything as a functor if it's found as an arguement to a predicate. foo(5+6). Foo gets passed the functor 5+6 == +(5,6), not 11.
Recursion, not for-loops. X = Y unifies; X is Y+1 evaluates Y+1. Facts, not functions. Each fact and rule should be literally correct, taken as a statement by itself. Prolog is weakly typed. The query member([1,2,3],1). will just fail and not give any warning. Upper case means variables, lower case for everything else member(X,[x,y,z]) and member(x,[x,y,z]) gives completely different results. The prolog buffer is for queries, not programming. Unlike languages like Python, Perl, Ruby etc, you cannot create new predicates in the prolog buffer, only query the existing set. Use the evaluate region/file/buffer commands in emacs.
vs
reverse2([],[]). reverse2([X],[X]). reverse2([Hx|Tailx],[Hy|Taily]) :append(Midx,[Hy],Tailx), reverse2(Midx,Midy), append(Midy,[Hx],Taily).
Be careful when you reorder clauses It's very easy to forget to change commas and periods. Sicstus allows infinite structures to be created.
| ?- X = [1|X]. X = [1,1,1,1,1,1,1,1,1,1|...] ?
This can be occationally be useful, but it can also be a source of confusing bugs.