570 likes | 725 Views
"Programming Paradigms", Dept. of Computer Science, Aalborg Uni. (Fall 2009). L OGIC P ROGRAMMING with P ROLOG. Claus Brabrand brabrand@itu.dk IT University of Copenhagen [ http://www.itu.dk/people/brabrand/ ]. Plan for Today. Lecture: "Lists and Arithmetic" ( 10:15 – 11:00 )
E N D
"Programming Paradigms", Dept. of Computer Science, Aalborg Uni. (Fall 2009) LOGIC PROGRAMMINGwith PROLOG Claus Brabrand brabrand@itu.dk IT University of Copenhagen [http://www.itu.dk/people/brabrand/]
Plan for Today • Lecture: "Lists and Arithmetic" (10:15 – 11:00) • Exercise 1, 2, and 3 (11:15 – 12:00) • Lunch break (12:00 – 12:30) • Lecture: "Reversibility, Cut, Negation, and Language Interpretation" (12:30 – 13:15) • Lecture: "Non-termination and Undecidability” (13:30 – 14:00) • Exercises 4, 5, and 6 (14:15 – 16:15)
Outline • Part 1: • Lists • Arithmetic • Part 2: • Reversibility • Cut and Negation • Language Interpretation • Part 3: • Non-termination • Undecidability
PROLOG's Search Order axioms (5x) f(a). f(b). g(a). g(b). h(b). k(X) :- f(X),g(X),h(X). rule (1x) rule body rule head • Resolution: • 1. Search knowledge base (from top to bottom) for(axiomor rule head) matching with (first)goal: • Axiom match:remove goal and process nextgoal[1] • Rule match: (as in this case): [2] • No match:backtrack(= undo; try next choice in 1.) [1] • 2. "-convert" variables (to avoid name clashes, later): • Goal: (record “Y = _G225”) • Match: [3] • 3. Replace goal with rule body: • Now resolvenew goals (from left to right); [1] k(Y) k(X) :- f(X),g(X),h(X). k(_G225) k(_G225) :- f(_G225),g(_G225),h(_G225). f(_G225),g(_G225),h(_G225). Possible outcomes: - success: no more goals to match (all matched w/ axioms and removed) - failure: unmatched goal (tried all possibilities: exhaustive backtracking) -non-termination: inherent risk (same- / bigger-and-bigger- / more-and-more -goals)
LISTS Keywords: (Encoded) lists, (built-in) lists, efficiency issues, ...
Lists (home-made) • Lists are easily represented: • // empty list • // construct new list from element and list • Example: • The list [1,2,3] may be representedas: • i.e., "representation of information" • Now, let's look at: ~Haskell nil cons(E,L) cons(1, cons(2, cons(3, nil))) "Transformation of representation of information" (= programming)
T Lists (example "functions") • Length: • Member: • Using underscore '_'(anonymous "ignore" variable)may improve readability len(0, nil). len(succ(N), cons(_, L)) :- len(N, L). len(0, nil). len(succ(N), cons(E, L)) :- len(N, L). member(X, cons(X, _)). member(X, cons(_, L)) :- member(X, L). member(X, cons(X, L)). member(X, cons(E, L)) :- member(X, L). PROLOG also has built-in lists; let’s have a look at them…
Lists (built-in) • Constant lists: • // the empty list • // constant list • Lists are (also) untyped;=finite sequence of (any) terms: • [] • [ [] ] • [ vincent, jules, marcellus ] • [ [], mia, 42, 'The Gimp', dead(zed), Z ] • [ [], [], [ [] ], [ [ x, X , [] ] ] ] ~Haskell [] [ X, Y, Z ] Q: What is the length of the lists?
The Head-Tail Constructor • PROLOG(like many other languages) has: • // "head-tail constructor" • Hhead (element) of list, Ttail of list (rest) • for construction and deconstruction: (bigger) list element and (smaller) list • Example: “construction”: • Example: “deconstruction”: ~Haskell h:t [ H | T ] ?- [ a | [b,c] ]= L. L = [a,b,c] ?- [a,b,c]= [ H | T ]. H = a T = [b,c]
Examples: “[ H | T ]” • Empty list example: • Mixed type example: • Tricky’ish example: ?- []= [ H | T ]. No ?- [ [], mia, 42, 'The Gimp', dead(zed), Z ]= [ X | Y ]. X = [] Y = [ mia, 42, 'The Gimp', dead(zed), _G225 ] Z = _G225 ?- [ [], [] ] = [ X | Y ]. X = [] Y = [ [] ]
Length and Member (revisited) ~ Haskell • Length/2: • Member/2: • Usage: len(0, []). len(succ(N), [ _|L ]) :- len(N, L). member(X, [ X|_ ]). member(X, [ _|L ]) :- member(X, L). ?- member(2, [1,2,3]). Yes ?- member(X, [1,2,3]). // gimme elements from list X=1 ; // next... X=2 ; X=3 ; No
T Append append([], L, L). append([X|L1], L2, [X|L3]) :- append(L1,L2,L3). • Append/3: Search treefor: ?- append([a,b,c], [d,e,f], R) R= [a,b,c,d,e,f] append([a,b,c],[d,e,f],_G1) append([a,b,c],[d,e,f],[a,b,c,d,e,f]) rule _G1 = [a|_G2] append([b,c],[d,e,f],_G2) append([b,c],[d,e,f],[b,c,d,e,f]) _G2 = [b|_G3] rule append([c],[d,e,f],_G3) append([c],[d,e,f],[c,d,e,f]) rule _G3 = [c|_G4] append([],[d,e,f],_G4) append([],[d,e,f],[d,e,f]) axiom _G4 = [d,e,f]
Using Append • Prefix/2: • Suffix/2: • SubList/2: ...alternatively...: prefix(P, L) :- append(P, _, L). suffix(S, L) :- append(_, S, L). subList(Lsub, L) :- suffix(S, L), prefix(Lsub, S). subList(Lsub, L) :- prefix(P, L), suffix(Lsub, P).
Reverse (and efficiency issues) • Reverse/2: • Idea; exploit property: “(x L)R = LR x” • Problem: [X|L] is asymmetrically left-to-right biased we cannot put the list in front and write: “[ L | X ]” • Let's useappend: rev([], []). rev([X|L], R) :- rev(L, L_rev), [L_rev | X] = R. rev([X|L], R) :- rev(L, L_rev), append(L_rev, [X], R). Q: What about efficiency? 1) …of append? ; 2) …of reverse?
Recall ("big-Odefinition"): f O(g) def n,k>0: N>n => |f(N)| k·|g(N)| "f is dominated by g for large values (larger than n)" Efficiency • Efficiency(append): • Efficiency(reverse): |arg1|+1 app([], L, L). app([X|L1], L2, [X|L3]) :- app(L1,L2,L3). O(|arg1|) rev([], []). rev([H|T], R) :- rev(T,TR), app(TR,[H],R). Q: Efficiency(reverse)...?
Search Tree: rev rev([], []). rev([H|T], R) :- rev(T,TR), app(TR,[H],R). rev([1, 2, 3], _G1) rev rule rev([2, 3], _G2), app(_G2, [1], _G1) |L|+1 steps (of reverse) rev rule O(|L|) rev([3], _G3), app(_G3, [2], _G2), app(_G2, [1], _G1) rev rule rev([], _G4), app(_G4, [3], _G3), app(_G3, [2], _G2), app(_G2, [1], _G1) + _G4 = [] rev axiom app([], [3], _G3), app(_G3, [2], _G2), app(_G2, [1], _G1) _G3 = [3] (1 step of append) app([3], [2], _G2), app(_G2, [1], _G1) 1+2+3 steps (of append) _G2 = [3,2] (2 steps of append) O(|L|2) app([3,2], [1], _G1) _G1 = [3,2,1] (3' append)
T Accumulator • Let's use an accumulator: ~ Haskell accRev([H|T], A, R) :- accRev(T, [H|A], R). accRev([], A, A). rev(L, R) :- accRev(L, [], R). oldRev vs. newRev: rev([1,2,3], _G1) 1 step (of rev) steps rev rule + O(n2) accRev([1,2,3], [], _G1) accRev rule oldRev accRev([2,3], [1], _G1) |L| steps (of accRev) accRev rule O(|L|) O(n) accRev([3], [2,1], _G1) newRev accRev rule accRev([], [3,2,1], _G1) 0 1 2 3 4 5 6 7 8 |L|
ARITHMETIC Keywords: Evaluation, ...
Binary Infix Functors: {+,-,*,/} • Consider: • What is going on...?!? • The symbols {+,-,*,/} are just: • (Binary) infix functors: • i.e., "2+2" is just a short-hand for "+(2,2)"; • in fact: ?-2+2 = 4 No ?-2*2 = 4 No ?-2-2 = 0 No ?-2/2 = 1 No ~ Haskell ?-2+2 = +(2,2) Yes
Binary Infix Functors (cont'd) • The symbols {+,-,*,/} just (conveniently)represent structured information: • is understood as • precedence:{*,/}stronger-than{+,-} • associativity:{+,-,*,/}left-associative • ...and is thus just a short-hand for: • ...which is, structurally, no different than: • However, their interpretation may be very different;e.g., "represents" an expression that may be evaluated 1-2/3+4*5*6 (1-(2/3))+((4*5)*6) "standard" precedence/ associativityrules +(-(1,/(2,3)),*(*(4,5),6) a(b(1,c(2,3)),d(d(4,5),6) ~ Haskell
The "is/2" Predicate • is/2 TERM TERM: • Evaluatesits right argument(as arithmetic expression) • ...provided all variables are instantiated! • Example (in predicate definition): ?-4 is 2+2 Yes ?-2+2 is 4 No ?-Xis 2+2 X=4 ?-2+2 isX *** ERROR: is/2: uninstantiated argument sq(X,Y) :- YisX*X. ?- sq(5,Y). Y=25 ?- sq(X,25). *** ERROR: is/2: uninstantiated argument
T Careful w/ Arithmetic Evaluation ...with unary encoding of numerals: • Recall "len/2": • Arithmetic version(s): len([], 0). len([_|L], succ(N)) :- len(L, N). len1([], 0). len1([_|L], N_succ) :- len1(L, N), NisN_succ-1. ?-len1([1,2,3], R). *** ERROR: is/2: uninstantiated argument len2([], 0). len2([_|L], N) :- len2(L, N_pred), NisN_pred+1. ?-len2([1,2,3], R). R=3 len3([], 0). len3([_|L], N) :- NisN_pred+1, len3(L, N_pred). -?len3([1,2,3], R). *** ERROR: is/2: uninstantiated argument
Accumulators (revisited) • "len/2": • Version withaccumulator: len([], 0). len([_|T], N) :- len(T, X), NisX+1. accLen([], A, A). accLen([_|T], A, N) :- AnewisA+1, accLen(T, Anew, N) len(List, Length) :- accLen(List, 0, Length). Same #steps (both 7x)… len([1,2,3], _G1) accLen([1,2,3], 0, _G1) However;NOT tail recursive: "calculation after recursion" len rule accLen rule; then "is" len([2,3], _G2), _G1 is _G2+1 accLen([2,3], 1, _G1) len rule accLen rule; then "is" len([3], _G3), _G2 is _G3+1, _G1 is _G2+1 accLen([3], 2, _G1) O(n) wide! len rule accLen rule; then "is" len([], _G4), _G3 is _G4+1, _G2 is _G3+1, _G1 is _G2+1 accLen([], 3, _G1) accLen axiom len axiom is is is Tail recursive! "calculation during recursion" _G3 is 0+1, _G2 is _G3+1, _G1 is _G2+1 ~ Haskell
Comparison Operators • More integer comparison operators (with arithmetic evaluation side-effects): • "<""less than" • "<=""less than or equal to" • ">""greater than" • ">=""greater than or equal to" • "=:=""equal to" • "=\=""not equal to" • Evaluate both arguments • Again, all variables have to be instantiated • Otherwise no surprises...
Exercise 1, 2, and 3: 11:15 – 12:00
1. ... • Purpose: • Learn how to ...
2. ... • Purpose: • Learn how to ...
3. ... • Purpose: • Learn how to ...
Ex: Symbolic Differentiation • Symbolic differentiation: d dx d dx (k) = 0 (xn) = n * xn-1 d dx d dx (x) = 1 (ex) = ex 1 x d dx d dx d dx d dx (f+g) = (f) + (g) (ln(x)) = d dx d dx d dx d dx (f-g) = (f) - (g) (sin(x)) = cos(x) d dx d dx d dx d dx (f*g) = f (g) + g (f) (cos(x)) = -sin(x) d dx d dx g (f) + f ( ) (g) d dx d dx d dx d dx (f/g) = (gof) = (g)o f * (f) g * g
...in PROLOG ex • In PROLOG: dX(K, 0) :- number(K). // constant dX(x, 1). // variable dX(F+G, Df+Dg) :- dX(F,Df), dX(G,Dg). // add dX(F-G, Df-Dg) :- dX(F,Df), dX(G,Dg). // sub dX(F*G, Df*G+F*Dg) :- dX(F, Df), dX(G, Dg). // mul dX(F/G, (Df*G-F*Dg)/(G*G)) :- dX(F, Df), dX(G, Dg). // div [...] dX(cos(x), 0-sin(x)). // cos dX(F;G, (F;Dg)*Df) :- dX(F,Df), dX(G,Dg). // compose
Differentiation • Interaction: • Reverse: • Does this mean we can do integration? • No, just certain functions in "anti - normal form" (ANF); i.e., functions that are in the image of the differentiation ?- dX(x/exp(x), Df). Df=(1*exp(x)-x*exp(x)) / (exp(x)*exp(x)) ?- dX(F,(1*exp(x)-x*exp(x)) / (exp(x)*exp(x))). F=x/exp(x) ANF f' f
CUT AND NEGATION Keywords (chapter 10): Side-effect, Backtracking, Cut, Fail, Cut-Fail, Negation, ...
The Cut Operator: '!' • Consider max/3: • Cut, "!", (locally) disablesbacktracking • Cut version: • Note: this cut changes only efficiency properties = "Green Cut" max(X,Y,Y) :- X =< Y. max(X,Y,X) :- X > Y. Note: mutually exclusive conditions ?- max(3,4,M). M = 4 ?-; // backtracking now causes futile re-evaluation of max max(X,Y,Y) :- X =< Y , ! . // commit (throw away max-backtracking) max(X,Y,X) :- X > Y.
"Green Cuts" vs. "Red Cuts" • "Green cut" version: • Alternative "Red cut" version (= relying on cut): • Seems okay...: • ...but: max(X,Y,Y) :- X =< Y , ! . max(X,Y,X) :- X > Y. max(X,Y,Y) :- X =< Y , ! . max(X,Y,X). // only succeeds if above fails (...or?) ?-max(99,100,X). X = 100 // ok! ?-max(100,99,X). X = 100 // ok! Advice: "cut down on cut" ?- max(1,100,1). Yes // Oops!(evaluation never made it to the cut)
Fail and exception predicating • Consider: • ...but maybe Vincent likes all burgers, except "Big Kahuna burgers". • PROLOG features a built-in "fail/0"-predicate: • Syntax: • Semantics: "always fails (and forces backtracking)" enjoys(vincent, X) :- burger(X). fail enjoys(vincent, X) :- big_kahuna_burger(X), !, fail enjoys(vincent, X) :- burger(X). the rulerelies (operationally) on the cut = red cut big_kahuna_burger(b1). big_mac(b0). ?- enjoys(vincent, b0). Yes ?- enjoys(vincent, b1). No
The Cut-Fail Combination • The "cut-failcombination"... • ...expresses negation • ...and is so common that it is built-in: • not/1; equivalent to: • It's better to use "not" • it's a higher level abstraction (than cut-fail); However...: enjoys(vincent, X) :- big_kahuna_burger(X), !, fail enjoys(vincent, X) :- burger(X). not(Goal) :- Goal, !, fail. not(Goal). Cut has operationally(well-)defined semantics which relation ?! Isn't always "well-defined": |_ P(x) |_ P(x) Inf. Sys. vs. PROLOG p(x) :- not(p(x)).
If-then-else: "( A -> B ; C )" • PROLOG has an if-then-else construction: • Syntax: • ( A -> B ; C ) • Semantics: • "if A; then B, else C" • Alternative version of max/3: • ...using if-then-else: max(X,Y,Z) :- ( X =< Y -> Z = Y ; Z = X ).
LANGUAGE INTERPRETATION Keywords: Interpretation, Evaluation, Syntax, Semantics, ...
Expressions (and syntax vs. semantics) • Expressions: • Syntax: • Semantics(via evaluation relation: " |-eval Exp N"): Exp: N [const] : +(Exp,Exp) [add] : *(Exp,Exp) [mul] here in prefix notationjust to emphasize difference between syntax and semantics |_evalE1N1|_evalE2 N2 |_eval+(E1,E2)N [add] N = N1 N2 [const] semantic |_evalNN syntactic "+" |_evalE1N1|_evalE2N2 |_eval*(E1,E2)N [mul] N = N1 N2 multiple levels of abstraction...!
Alice and Knight talking Alice in Wonderland • Different levels of abstraction: • Things ‘A Sitting on a Gate’ • Names of things ‘The Aged Aged Man.’ • Things are called something ‘Ways and Means’ • Names are called something ‘Haddocks’ Eyes.’ K> "[...] The name of the song is called‘Haddocks’ Eyes.’” A> “Oh, that’s the name of the song, is it?” Alice said, trying to feel interested.K> “No, you don’t understand,” the Knight said, looking a little vexed. K> “That’s what the name is called. The name really is ‘The Aged Aged Man.’” A> “Then I ought to have said, ‘That’s what the song is called’?” Alice corrected herself. K> “No, you oughtn’t: that’s another thing. The song is called‘Ways and Means’: K> but that’s only what it’s called, you know!” A> “Well, what is the song, then?” said Alice, who was by this time completely bewildered. K> “I was coming to that,” the Knight said. “The song really is‘A Sitting on a Gate’: K> and the tune’s my own invention.”
[...back to]:(syntax vs. semantics) • Expressions: • Syntax: • Semantics(via evaluation relation: " |-eval Exp N"): Exp: N [const] : +(Exp,Exp) [add] : *(Exp,Exp) [mul] here in prefix notationjust to emphasize difference between syntax and semantics |_evalE1N1|_evalE2 N2 |_eval+(E1,E2)N [add] N = N1 N2 [const] semantic |_evalNN syntactic "+" |_evalE1N1|_evalE2N2 |_eval*(E1,E2)N [mul] N = N1 N2
Expressions (in PROLOG) • Syntax: • Semantics: exp(con(N)) :- number(N). exp(add(E1,E2)) :- exp(E1), exp(E2). exp(mul(E1,E2)) :- exp(E1), exp(E2). ?-exp(mul(add(con(2),con(4)),con(7))). Yes eval(con(N), N). eval(add(E1,E2),N) :- eval(E1,N1), eval(E2,N2), N is N1 + N2. eval(mul(E1,E2),N) :- eval(E1,N1), eval(E2,N2), N is N1 * N2. ?-eval(mul(add(con(2),con(4)),con(7)),X). X = 42 binary infix syntax binary infix syntax eval(N, N) :- number(N). eval(E1+E2,N):- eval(E1,N1), eval(E2,N2), N is N1 + N2. eval(E1*E2,N):- eval(E1,N1), eval(E2,N2), N is N1 * N2. ?-eval((2+4)*7,X). X = 42
The "WHILE" Language • The "WHILE" Language: • Syntax: • Semantics: • Similar techniques (albeit somewhat more complicated)... Exp : N// const : X// var : ExpExp, {+,-,*,/}// binop Com : skip// skip : X := Exp// assign : if ( Exp ) thenComelseCom// if : while( Exp ) doCom// while : Com; Com// sequence
The Lambda Calculus • The Lambda Calculus • Syntax: • Semantics (call-by-value): You only have to understand here that The Lambda Calculus can be encoded in PROLOG : VAR Z Note: this is a variant of the semantics you saw earlier
The Lambda Calculus (in PROLOG) • Syntax: • << Exercise 4 >> • Semantics: • Similar techniques (as with the expression language) ?- eval(apply(lambda(x,variable(x)), lambda(y,variable(y)), Res). Res = lambda(y,variable(y))
NON-TERMINATION Keywords: Turing-Completeness, Reduction, Self-referentiality, Undecidability, ...
Prolog • A French programming language (from 1971): • "Programmation en Logique"(="programming in logic") • A declarative, relationalstyle of programming based on first-order logic: • Originally intended for natural-language processing, but has been used for many different purposes (esp. for programming artificial intelligence). • The programmer writes a "database" of "facts" and "rules"; e.g.: • The user then supplies a "goal" which the system attempts toprove(using resolution and backtracking); e.g., witch(girl). %- RULES ---------- witch(X) :- burns(X) , female(X). burns(X) :- wooden(X). wooden(X) :- floats(X). floats(X) :- sameweight(X,Y) , floats(Y). %- FACTS ---------- female(girl). floats(duck). sameweight(girl,duck).
Undecidability • Consider "The Book-of-all-Books": • This book contains the titles of all books that do not have a self-reference(i.e. don't contain their title inside) • Finitely many books; i.e.: • We can sit down & figure out whether to include or not... • Q: What about "The Book-of-all-Books"; • Should it be included or not? • "Self-referential paradox"(many guises): • e.g. "Thissentence is false" "The Bible" "War and Peace" "ProgrammingLanguages, An Interp.-Based Approach" ... The Book-of-all-Books
Undecidability (of Termination) • Assume termination is decidable (in Java); • i.e. some program, halts: PROG BOOL • Q: Does P0loop or terminate...? :) • Hence: "Termination is undecidable" • ...for WHILE, Java, C, Lambda Calculus, Prolog, ... boolhalts(prog p) { ... } -- P0.prg -- prog p0 = read_program("P0.prg"); if (halts(p0) == "halts") loop(); elsehalt();