CS 541 Lecture -*- Outline -*- * higher order features of lambda prolog reference: An Overview of Lambda Prolog by Nadathur and Miller (5th Intl. Conf. on Logic Prog., MIT Press, 1988) and Dale Miller's notes, chapters 6 and 5 def: a predicate is higher-order iff it does not have a type of the form T -> S -> ... -> o. e.g., T -> (S -> U) -> o is higher-order. ** lambda terms *** syntax chapter 6 ------------------------------------------ LAMBDA TERMS in \Prolog syntax: (var \ body) (var : type \ body) examples: (x \ x) (i \ (s (s i))) (x \ (T \ type_of H x T)) ------------------------------------------ (x \ P) means lambda x . P (x : T \ P) means lambda x:T . P Q: what's this like in SML or Haskell? mathematical notation is \x.P Try some examples like... $ tjsim unary [unary] ?- 1 = ((x \ x) 1). yes [unary] ?- to_nat 4 ((i \ (s (s i))) What). The answer substitution: What = s (s z) can use capital letters for the identifier, but not interpreted as logical vars, so best to use lower case. *** type rules ------------------------------------------ SOME TYPE RULES FOR \PROLOG |- M : [query] -------------- ?- M. checks |- M: [-> E] -------------------------- |- (M N): T [-> I] ---------------------- |- (x \ M): ------------------------------------------ Fill these in like below during class. H |- M : o [query] -------------- H ?- M. checks H |- M: S -> T, H |- N : S [-> E] -------------------------- H |- (M N): T H' |- M: T [-> I] ---------------------- where H' = [x |-> S]H H |- (x \ M): S -> T [var] H |- x : T where H(x) = T *** mapping see file maps.mod in this directory (modified from examples/utility/maps.mod in the Teyjus release) show how to develop something like map in Haskell, call it mapfun. in SML want mapfun f (X1::...::Xn::nil) to be (f X1)::...::(f Xn)::nil Q: so what would the type be in \Prolog? sig maps. type mapfun (A -> B) -> list A -> list B -> o. ... base case: mapfun F nil nil. inductive case: mapfun F (X :: L) _____________ :- mapfun F L K. examples $ tjsim unary_with_maps ?- mapfun s (z::(s z)::(s (s z))::nil) L. L = s z :: s (s z) :: s (s (s z)) :: nil. yes ?- mapfun (x \ (x::nil)) (1::2::3::nil) ResultList. ResultList = (1 :: nil) :: (2 :: nil) :: (3 :: nil) :: nil yes ?- reduce (x \ y \ x::x::y) (1::2::3::nil) nil Res. Res = 1 :: 1 :: 2 :: 2 :: 3 :: 3 :: nil. ; no more solutions ?- reduce (x \ y \ x) (1::2::3::nil) 50 Res. Res = 1 Q: what's the type of reduce? Q: can you write reduce of type (A -> B -> B) -> (list A) -> B -> B -> o ? Q: What's this like in Haskell? ------------------------------------------ sig inc. type inc int -> int -> o. module inc. inc N M :- M is N + 1. Using inc, how would you increment each element in a list of ints? I.e, what are M and I such that: ?- M I (5::8::2::nil) L. L = 6 :: 9 :: 3 :: nil. ------------------------------------------ Q: what goes wrong with mapfun and inc? doesn't type check this shows that using mapfun and functions aren't all you'd like. define and write mappred type mappred (A -> B -> o) -> (list A) -> (list B) -> o. % mappred P (X1::X2::...::Xn) (Y1::Y2::...::Yn) % Succeeds if the predicate P relates Xi to Yi. mappred P nil nil. mappred P (X :: L) (Y :: K) :- P X Y, mappred P L K. Q: can you write for_each of type for_each (A -> o) -> (list A) -> o. such that for_each P L succeeds if P is true for each element of list L? ** semantics of lambda abstractions (skip or go quickly if done already) Do the following examples. $ tjsim [toplevel] ?- (x \ x) = (y \ y). yes [toplevel] ?- (x \ F x) = (y \ F y). The answer substitution: F = F The remaining disagreement pairs list: More solutions (y/n)? y no (more) solutions [toplevel] ?- (x \ (y \ x)) = (z \ (y \ z)). yes [toplevel] ?- (x \ (y \ x)) = (y \ (y \ y)). no (more) solutions [toplevel] ?- (z \ (x \ y \ z)) = (z \ (z \ y \ z)). no (more) solutions We can generalize these rules to a rule called alpha conversion. Miller's notes, page 77 Notation: [y/x]M means M with all free occurrences of x replaced by y [alpha] (x \ M) = (y \ [y/x]M), if y is not free or bound in M. this is called alpha conversion; usually say two lambda terms are equal if they are alpha convertible. Some more examples sig unary_and_inc. accum_sig unary, inc. module unary_and_inc. accumulate unary, inc. $ tjsim unary_and_inc [unary_and_inc] ?- (x \ s (s x)) z = M. The answer substitution: M = s (s z) [unary_and_inc] ?- (x \ (F x)) Y = (F Y). The answer substitution: Y = Y F = F The remaining disagreement pairs list: [unary_and_inc] ?- (x \ s x) = s. yes [unary_and_inc] ?- (x \ (inc x)) = inc. yes [unary_and_inc] ?- (x \ (inc (inc x))) = inc. std_in:1.7: Error: clash in operator and operand type Expected operand type: int Actual operand type: (int -> o) in expression inc (inc x) std_in:1.23: Error: clash in operator and operand type Expected operand type: (int -> ERROR) Actual operand type: (int -> int -> o) in expression (x\ <>) = inc Q: what 2 rules can you derive from these examples? [beta] (x \ M) N = [N/x]M [eta] (x \ M x) = M, if m does not occur free in M The undirected rules are called conversions. Going from left to right is called a reduction, and from right to left is an expansion. Note that beta and eta are somewhat two sides of the same coin. (x \ M x) N = M N Q: how can these be used lambda-prolog or SML? beta is what we used to trace programs eta is used as follows... fun add_to_each n ls = map (fn x => x + n) ls ...can be simplified to what? ------------------------------------------ SUMMARY OF EQUATIONAL RULES FOR THE LAMBDA CALCULUS [alpha] (x \ M) = (y \ [y/x]M) if y is not free in M and y is not bound in M [beta] (x \ M) N = [N/x]M [eta] (x \ M x) = M if x is not free in M ------------------------------------------ example problems that demonstrate need for side conditions in alpha: (x \ y \ x), can't change x to y (y bound in (y \ x)) (x \ z), can't change x to z (z free in z) in eta: (x \ (f x) x) is not equal to (f x) ------------------------------------------ SUBSTITUTION [N/x]x = N [N/x]y = y, if y is not x [N/x](M M') = ([N/x]M [N/x]M') [N/x](x \ M) = (x \ M) [N/x](y \ M) = ((z \ [N/x]([z/y]M))), if y is not x and if x is not free in M or y is not free in N, then z is y, else z is not in M or N ------------------------------------------ example problem that demonstrate need for z different from y in the substitution into (y \ M): [(f y)/x](y \ x) is (z \ (f y)), not the captured (y \ (f y)) ------------------------------------------ FREE VARIABLES FV(x) = {x} FV(M M') = FV(M) union FV(M') FV(y \ M) = FV(M) - {y} ------------------------------------------ ** implication (=>) ref section 5.5 can write p => q to mean p implies q. exactly the same as writing q :- p. So in programs p => q means what q :- p means. But we haven't talked about what :- or => means in *queries* yet. *** examples of using => in queries ("what if" querries) Teyjus doesn't support this (yet)... so we use Terzo Terzo> #query some-facts. ?- (logician Y), (american Y). Y = ron ; no more solutions ?- (american sue) => ((logician Y), (american Y)). Y = sue ; Y = ron ; no more solutions ?- *** intuionistic examples that is, perhaps counter to your intuition... ------------------------------------------ module intuitionistic. type false o. type p o. type q o. type r o. ------------------------------------------ Terzo> #query intuitionstic. ?- false. no ?- false => (1 = 2). no % It assumed false, but that doesn't help prove 1=2. ?- p ; (p => q). no % It can't prove p, and then assuming p doesn't help prove q, as no rule connects them. *** semantics => in a query is interpreted intuitionistically ?- p => q means to assume p (as part of program) and try to prove q. this assumption like a new rule at the beginning of the program. ** universal quantifier (pi) ref: section 5.6 can write (pi x \ P) to mean ``for all x . P'' ------------------------------------------ sig qualifier_db. kind student type. kind class type. type john student. type mary student. type cs541 class. type cs542 class. type cs641 class. type passed student -> class -> o. type qualify student -> o. module qualifier_db. passed john cs541. passed mary cs541. passed mary cs542. passed mary cs641. % the following doesn't do what you think. qualify X :- (pi c \ (passed X c)). ------------------------------------------ Tracing from old version of lambda prolog (eLP) ... ?- trace all_goals. Solving ... Solving top ?- qualify mary. Solving ... Solving qualify mary Solving pi C: class \ (passed mary C) Solving passed mary c: class Goal passed mary c: class failed Goal pi C: class \ (passed mary C) failed Goal qualify mary failed no ?- the problem is that mary hasn't passed every class, just the ones listed so it can't be proved that she has passed an ARBITRARY class c. this is interpreted intuitionistically as the search rule AUGMENT ?- (pi x \ P) means to try to prove [c/x]P, where c is a fresh constant note: c is NOT a variable, and so doesn't unify... ------------------------------------------ sig qualifier_db_fixed. kind student type. kind class type. type john student. type mary student. type cs541 class. type cs542 class. type cs641 class. type passed student -> class -> o. type classes list class -> o. type qualify student -> o. module qualifier_db_fixed. import maps. passed john cs541. passed mary cs541. passed mary cs542. passed mary cs641. classes (cs541::cs542::cs641::nil). qualify X :- classes CL, for_each (passed X) CL. ------------------------------------------ for_each is defined in module maps. note the use of (passed X), which has type (class -> o); this shows the advantage of currying. note the use of classes, as a "global variable". [qualifier_db_fixed] ?- qualify mary. yes ** existential quantifier (sigma) (sigma x \ P x) means "for some x, (P x) holds" larch 1007$ tjsim some-facts [some-facts] ?- (logician X). The answer substitution: X = sue More solutions (y/n)? y The answer substitution: X = ron More solutions (y/n)? y no (more) solutions [some-facts] ?- (sigma x \ logician x). yes Q: So what's the difference between these queries? The interpretation is that you search for a solution, and forget what it was.