the logical burrito - pattern matching, term rewriting and unification

41
The Logical Burrito Episode I: The Road to Unification an exploration of pattern matching, term rewriting and unification (wrapped up in a warm flour tortilla) Norman Richards [email protected] @MaximoBurrito

Upload: norman-richards

Post on 16-Jul-2015

288 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: The Logical Burrito - pattern matching, term rewriting and unification

The Logical Burrito Episode I: The Road to Unification

an exploration of pattern matching, term rewriting and unification (wrapped up in a warm flour tortilla)

Norman Richards [email protected]

@MaximoBurrito

Page 2: The Logical Burrito - pattern matching, term rewriting and unification

Goals• Explore unification as groundwork for understanding logic

programming in general and core.logic (mini-kanren based) in specific

• Rather than focus on unification, this is a survey of some loosely related (in my mind) topics - pattern matching and and term rewriting

• Will demonstrate these ideas in other languages: ML for pattern matching, Mathematica for term rewriting, and Prolog for unification

Page 3: The Logical Burrito - pattern matching, term rewriting and unification

Pattern Matching

as a dispatch mechanism (or simple conditional) a way to express the selection criteria for which code to execute

Page 4: The Logical Burrito - pattern matching, term rewriting and unification

• In Clojure, dispatch is on arity: (defn foo ([x] …) ([x y] …))

• you can destructure but you can’t ask questions about the types or value

• OO dispatch - based on type of first arg (.getArea shape)

• Multiple dispatch - based on type of all args (method overriding is compile time) multimethods

Dispatch

Page 5: The Logical Burrito - pattern matching, term rewriting and unification

Multimethods

(defmulti fact identity)

(defmethod fact 0 [_] 1)

(defmethod fact :default [n] (* n (fact (dec n))))

Page 6: The Logical Burrito - pattern matching, term rewriting and unification

Multimethods

(defmulti fizzbuzz identity)

(defmethod fizzbuzz 1 [n] (str n)) (defmethod fizzbuzz 2 [n] (str n)) (defmethod fizzbuzz 3 [n] "fizz")

;; ... this isn't going to work

Page 7: The Logical Burrito - pattern matching, term rewriting and unification

Multimethods;; we can make arbitrary dispatch rules (defmulti fizzbuzz (fn [n] [(zero? (mod n 3)) (zero? (mod n 5))]))   ;; as long as we can match the defaults (defmethod fizzbuzz [true true] [n] "fizzbuzz") (defmethod fizzbuzz [true false] [n] "fizz") (defmethod fizzbuzz [false true] [n] "buzz") (defmethod fizzbuzz [false false] [n] (str n))

Page 8: The Logical Burrito - pattern matching, term rewriting and unification

Multimethods

(defmulti beats vector)

;; or if we have a single default value (defmethod beats :default [m1 m2] false) (defmethod beats [:paper :rock] [m1 m2] true) (defmethod beats [:rock :scissors] [m1 m2] true) (defmethod beats [:scissors :paper] [m1 m2] true)

Page 9: The Logical Burrito - pattern matching, term rewriting and unification

Multimethods

• Multimethods are great for what they do, but they aren't a replacement for pattern maching

• Clojure doesn't have great pattern matching, so we'll consider ML

Page 10: The Logical Burrito - pattern matching, term rewriting and unification

Pattern Matching (SML)

(* SML matching at the function level*)

fun fac 0 = 1 | fac n = n * fac (n - 1);

Page 11: The Logical Burrito - pattern matching, term rewriting and unification

Pattern Matching (SML)val div_3 = div_by 3; val div_5 = div_by 5;   (* No guard statements, but we can match in the body of the function on derived values *) fun fizzbuzz n = case (div_3 n, div_5 n) of (true, true) => "FizzBuzz" | (true, false) => "Fizz" | (false,true) => "Buzz" | _ => Int.toString n (* underscore matches anything *)

Page 12: The Logical Burrito - pattern matching, term rewriting and unification

Pattern Matching (SML)datatype suit = Clubs | Diamonds | Hearts | Spades datatype rank = Jack | Queen | King | Ace | Num of int type card = suit * rank datatype color = Red | Black   (* non-default don't cares exceed what multimethods can do *) fun card_color (Diamonds, _) = Red | card_color (Hearts , _) = Red | card_color _ = Black   (* note deep destructuring *) fun card_value (_, Num(n)) = n | card_value (_, Ace) = 11 | card_value _ = 10

Page 13: The Logical Burrito - pattern matching, term rewriting and unification

core.match(defn card_color [[suit value]] (match [suit value] [:diamonds _] :red [:hearts _] :red [_ _] :black))    (defn card_value [card] (match card [_ (n :guard number?)] n [_ :ace] 11 :else 10))  

Page 14: The Logical Burrito - pattern matching, term rewriting and unification

Limitations of core.match

• No defnm to use at language level

• Syntax can be ugly

• Can't match non-linear patterns: [n n]

Page 15: The Logical Burrito - pattern matching, term rewriting and unification

(define eval-exp (lambda (expr env) (pmatch expr [,x (guard (symbol? x)) ;; variable (lookup x env)] [(quote ,datum) datum] [(list . ,expr*) ;; (map (lambda (expr) (eval-exp expr env)) expr*) (eval-exp* expr* env)] [(lambda (,x) ,body) ;; abstraction `(closure ,x ,body ,env)] [(,e1 ,e2) ;; application (let ((proc (eval-exp e1 env)) (val (eval-exp e2 env))) (pmatch proc [(closure ,x ,body ,envˆ) ;; evaluate body in an extended environment (eval-exp body `((,x . ,val) . ,envˆ))] [,else (error 'eval-exp "e1 does not evaluate to a procedure")]))])))

A scheme example (pmatch)

Page 16: The Logical Burrito - pattern matching, term rewriting and unification

Term rewriting

Term rewriting is a branch of theoretical computer science which combines elements of logic, universal algebra, automated theorem proving and functional programming.  [...] This constitutes a Turing-complete computational model which is very close to functional programming.

- Term Rewriting and All That

Page 17: The Logical Burrito - pattern matching, term rewriting and unification

Mathematica

The innermost kernel of the Mathematica language is essentially nothing else than a higher-order, conditional rewrite language, efficiently and professionally implemented.

- Mathematica as a Rewrite Language (Bruno Buchberger)

Page 18: The Logical Burrito - pattern matching, term rewriting and unification

Rewriting in Mathematica

In[1]:= sum[m_, 0] := m; sum[m_, s[n_]] := s[sum[m, n]];

In[3]:= sum[s[s[0]], s[s[s[s[0]]]]] 

Out[3]= s[s[s[s[s[s[0]]]]]]

Page 19: The Logical Burrito - pattern matching, term rewriting and unification

Rewriting in Mathematica

In[4]:= map[f_, {}] := {}; map[f_, {x_, xs___}] := Prepend[map[f, {xs}], f[x]];   In[6]:= map[something, {1, 2, 3, 4, 5}]   Out[6]= {something[1], something[2], something[3], something[4], something[5]}

Page 20: The Logical Burrito - pattern matching, term rewriting and unification

Rewriting in Mathematica

In[7]:= something[n_] := dont_care /; OddQ[n]   In[8]:= map[something, {1, 2, 3, 4, 5}]   Out[8]= {dont_care, something[2], dont_care, something[4], dont_care}

Page 21: The Logical Burrito - pattern matching, term rewriting and unification

Rewriting in Clojure (termito)

(defrules s-rule [(+ ?x 0) ?x] [(+ ?x (s ?y)) (s (+ ?x ?y))])

(simplify '(+ (s (s 0)) (s (s (s (s 0))))) s-rule)

;; (s (s (s (s (s (s 0))))))

Page 22: The Logical Burrito - pattern matching, term rewriting and unification

Rewriting in Clojure (termito)(defnc numbers [x] (number? x)) (defnc commutative? [op] (or (= op '*) (= op '+))) (defnc associative? [op] (or (= op '*) (= op '+)))

(defrules zero-rules [(* 0 ?x) 0]) (defrules identity-rules [(* 1 ?x) ?x] [(+ 0 ?x) ?x]) (defrules associative-rules [(?op ?x (?op ?y ?z)) :when [?op ~associative? #{?x ?y} ~numberc] (?op (?op ?x ?y) ?z)])

Page 23: The Logical Burrito - pattern matching, term rewriting and unification

Unification

Unification is a basic operation on terms.  Two terms unify if substitutions can be made for any variables in the terms so that the terms are made identical.   If no such substitution exists, then the terms do not unify.

- Clause and Effect

Page 24: The Logical Burrito - pattern matching, term rewriting and unification

Unification with Prolog

?- 42 = 42. true.

?- six_times_nine = 42. false.

?- enough = enough. true.

Constants unify with themselves

Page 25: The Logical Burrito - pattern matching, term rewriting and unification

Unification with Prolog

?- City = austin. City = austin.

?- 7 = Number. Number = 7.

uninstantiated logic variables unify with constants.

Page 26: The Logical Burrito - pattern matching, term rewriting and unification

Unification with Prolog

?- X = Y. X = Y.

?- A=B, C=D, C=B. A = B, B = C, C = D.

uninstantiated variables unify with each other and co-refer

Page 27: The Logical Burrito - pattern matching, term rewriting and unification

Unification with Prolog

?- A=B, C=D, C=B, A=pi. A = B, B = C, C = D, D = pi.

?- A=B, C=D, C=B, A=pi, D=tau. false.

uninstantiated variables unify with each other and co-refer

Page 28: The Logical Burrito - pattern matching, term rewriting and unification

Unification with Prolog

?- foo(1) = x. false.

?- foo(1) = foo(2). false.

?- foo(X) = bar(X). false.

?- foo(X) = foo(Y). X = Y.

complex terms unify if they have the same head and all their parts unify

Page 29: The Logical Burrito - pattern matching, term rewriting and unification

Unification with Prolog?- foo(X,Y)=foo(2,3). X = 2, Y = 3.

?- foo(X,5) = foo(7,Y). X = 7, Y = 5.

?- foo(X,5) = foo(9,X). false.

Page 30: The Logical Burrito - pattern matching, term rewriting and unification

Unification with Prolog

?- foo(A,B,B) = foo(B, B, A). A = B.

?- foo(bar(Z)) = foo(X), X= bar(baz). Z = baz, X = bar(baz).

?- f(X, a(b,c)) = f(d, a(Z,c)). X = d, Z = b.

Page 31: The Logical Burrito - pattern matching, term rewriting and unification

Unification with Clojure

• core.logic unifier has more features, more actively maintained

• core.unify has the prettier API, less baggage

Page 32: The Logical Burrito - pattern matching, term rewriting and unification

core.unify vs core.logic

• core.logic • (unify [1 '?x])  => 1 • (unifier [1 '?x]) ==> {?x 1}

• core.unify • (unify 1 '?x) ==> {?x 1} • (unifier 1 '?x) ==> 1

Page 33: The Logical Burrito - pattern matching, term rewriting and unification

core.logic unification(unifier '[dog dog]) ;; {}

(unifier '[dog cat]) ;; nil

(unifier '[?animal dog]) ;; {?animal dog}   (unifier '[?foo ?bar]) ;; {?foo ?bar}

Page 34: The Logical Burrito - pattern matching, term rewriting and unification

core.logic unification

(unifier '[{:name bob :age 42} {:name ?X :age ?Y}]) ;; {?X bob, ?Y 42}   (unifier '[{:name bob :age 42} {:name ?X}]) ;; nil

Page 35: The Logical Burrito - pattern matching, term rewriting and unification

core.logic unification

(unifier {:when {'?num numberc}} '[[?num ?animal] [:magical :unicorn]]) ;; nil   (unifier {:when {'?num numberc}} '[[?num ?animal] [42 :unicorn]]) ;; {?animal :unicorn, ?num 42}

Page 36: The Logical Burrito - pattern matching, term rewriting and unification

core.logic unification(unifier {:as '{?a 3}} '[?a ?b]) ;; {?b 3, ?a 3}   (unifier {:as '{?a 3 ?b 4}} '[?a ?b]) ;; nil

(unifier {:as (unifier '[?a ?b])} '[(?c 5) (?a ?b)]) ;; {?b 5, ?a 5, ?c 5}

Page 37: The Logical Burrito - pattern matching, term rewriting and unification

(defn unifier+ [& pairs] (loop [u {} pairs pairs] (if (seq pairs) (when-let [u' (unifier {:as u} (first pairs))] (recur (merge u u') (rest pairs))) u)))

(unifier+ '[?x 1] '[?y 2] '[?z [?x ?y]]) ;; {?z [1 2], ?y 2, ?x 1}

core.logic unification

Page 38: The Logical Burrito - pattern matching, term rewriting and unification

(defn q [data query] (filter #(unifier+ (conj query %)) data))

(def things [{:name "thing 1" :color :red} {:name "thing 2" :color :blue} {:name "thing 3" :color :red}])   (q things '[{:name ?name :color :red}]) ;; ({:color :red, :name "thing 1"} {:color :red, :name "thing 3"})

core.logic unification

Page 39: The Logical Burrito - pattern matching, term rewriting and unification

Why?

• Logic programming

• Machine Learning / Natural language processing

• Type inferencing / type checking

• Theorem proving / Equation solving

Page 40: The Logical Burrito - pattern matching, term rewriting and unification
Page 41: The Logical Burrito - pattern matching, term rewriting and unification

Until the next logical burrito,

(run* [your-location] (conde [(== your-location :home)] [succeed]) (!= your-location :here))

Norman Richards [email protected]

@MaximoBurrito