SlideShare a Scribd company logo
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
orb@nostacktrace.com
@MaximoBurrito
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
Pattern Matching
as a dispatch mechanism (or simple conditional)
a way to express the selection criteria for which code to execute
• 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
Multimethods
(defmulti fact identity)
(defmethod fact 0 [_]
1)
(defmethod fact :default [n]
(* n (fact (dec n))))
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
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))
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)
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
Pattern Matching (SML)
(* SML matching at the function level*)
fun fac 0 = 1
| fac n = n * fac (n - 1);
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
*)
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
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))
 
Limitations of core.match
• No defnm to use at language level
• Syntax can be ugly
• Can't match non-linear patterns: [n n]
(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)
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
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)
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]]]]]]
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]}
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}
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))))))
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)])
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
Unification with Prolog
?- 42 = 42.
true.
?- six_times_nine = 42.
false.
?- enough = enough.
true.
Constants unify with themselves
Unification with Prolog
?- City = austin.
City = austin.
?- 7 = Number.
Number = 7.
uninstantiated logic variables unify with constants.
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
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
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
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.
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.
Unification with Clojure
• core.logic unifier has more features, more actively maintained
• core.unify has the prettier API, less baggage
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
core.logic unification
(unifier '[dog dog])
;; {}
(unifier '[dog cat])
;; nil
(unifier '[?animal dog])
;; {?animal dog}
 
(unifier '[?foo ?bar])
;; {?foo ?bar}
core.logic unification
(unifier '[{:name bob :age 42}
{:name ?X :age ?Y}])
;; {?X bob, ?Y 42}
 
(unifier '[{:name bob :age 42}
{:name ?X}])
;; nil
core.logic unification
(unifier {:when {'?num numberc}}
'[[?num ?animal] [:magical :unicorn]])
;; nil
 
(unifier {:when {'?num numberc}}
'[[?num ?animal] [42 :unicorn]])
;; {?animal :unicorn, ?num 42}
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}
(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
(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
Why?
• Logic programming
• Machine Learning / Natural language processing
• Type inferencing / type checking
• Theorem proving / Equation solving
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
orb@nostacktrace.com
@MaximoBurrito

More Related Content

PDF
core.logic introduction
PDF
Clojure: The Art of Abstraction
PDF
Predictably
PDF
Sneaking inside Kotlin features
PDF
Clojure class
PDF
What can be done with Java, but should better be done with Erlang (@pavlobaron)
PDF
Clojure for Java developers - Stockholm
PDF
JavaOne 2013 - Clojure for Java Developers
core.logic introduction
Clojure: The Art of Abstraction
Predictably
Sneaking inside Kotlin features
Clojure class
What can be done with Java, but should better be done with Erlang (@pavlobaron)
Clojure for Java developers - Stockholm
JavaOne 2013 - Clojure for Java Developers

What's hot (19)

PPTX
CodeCamp Iasi 10 march 2012 - Practical Groovy
PPTX
Introduction to kotlin + spring boot demo
PPTX
Clojure for Data Science
PPTX
Introduction to Gremlin
PDF
Hw09 Hadoop + Clojure
PDF
Haskell in the Real World
PDF
concurrency with GPars
PDF
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
PDF
Hadoop + Clojure
PDF
Python dictionary : past, present, future
PDF
Pragmatic Real-World Scala (short version)
ODP
GPars (Groovy Parallel Systems)
PDF
Scala vs java 8
PPTX
concurrency gpars
PDF
Hammurabi
PDF
Idiomatic Kotlin
PDF
From Lisp to Clojure/Incanter and RAn Introduction
PDF
Let the type system be your friend
PDF
Why Haskell
CodeCamp Iasi 10 march 2012 - Practical Groovy
Introduction to kotlin + spring boot demo
Clojure for Data Science
Introduction to Gremlin
Hw09 Hadoop + Clojure
Haskell in the Real World
concurrency with GPars
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
Hadoop + Clojure
Python dictionary : past, present, future
Pragmatic Real-World Scala (short version)
GPars (Groovy Parallel Systems)
Scala vs java 8
concurrency gpars
Hammurabi
Idiomatic Kotlin
From Lisp to Clojure/Incanter and RAn Introduction
Let the type system be your friend
Why Haskell
Ad

Similar to The Logical Burrito - pattern matching, term rewriting and unification (20)

PDF
Real World Haskell: Lecture 2
PDF
Implementing pattern-matching in JavaScript (full version)
PDF
Functional programming in ruby
PDF
Dynamic Semantics
PDF
Clojure intro
PDF
Thinking Functionally In Ruby
PDF
Monads and Monoids by Oleksiy Dyagilev
PDF
Scala: Functioneel programmeren in een object georiënteerde wereld
PDF
Functional programming ii
PPTX
PDF
PDF
Pune Clojure Course Outline
PDF
Power of functions in a typed world
PPT
Sorting Seminar Presentation by Ashin Guha Majumder
PDF
Pydiomatic
PDF
Python idiomatico
PDF
ODP
Introduction to R
PPTX
Scala - where objects and functions meet
PDF
Ejercicios de estilo en la programación
Real World Haskell: Lecture 2
Implementing pattern-matching in JavaScript (full version)
Functional programming in ruby
Dynamic Semantics
Clojure intro
Thinking Functionally In Ruby
Monads and Monoids by Oleksiy Dyagilev
Scala: Functioneel programmeren in een object georiënteerde wereld
Functional programming ii
Pune Clojure Course Outline
Power of functions in a typed world
Sorting Seminar Presentation by Ashin Guha Majumder
Pydiomatic
Python idiomatico
Introduction to R
Scala - where objects and functions meet
Ejercicios de estilo en la programación
Ad

More from Norman Richards (7)

PDF
An Adventure in Serverless ClojureScript
PDF
Logic programming a ruby perspective
PDF
Lisp 1.5 - Running history
PDF
Deconstructing the Functional Web with Clojure
PDF
Immutant
PDF
Vert.X mini-talk
PDF
The Lambda Calculus and The JavaScript
An Adventure in Serverless ClojureScript
Logic programming a ruby perspective
Lisp 1.5 - Running history
Deconstructing the Functional Web with Clojure
Immutant
Vert.X mini-talk
The Lambda Calculus and The JavaScript

Recently uploaded (20)

PDF
CIFDAQ's Market Insight: SEC Turns Pro Crypto
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Empathic Computing: Creating Shared Understanding
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
Encapsulation theory and applications.pdf
PDF
Machine learning based COVID-19 study performance prediction
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
cuic standard and advanced reporting.pdf
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
NewMind AI Monthly Chronicles - July 2025
PPTX
A Presentation on Artificial Intelligence
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
CIFDAQ's Market Insight: SEC Turns Pro Crypto
Reach Out and Touch Someone: Haptics and Empathic Computing
Empathic Computing: Creating Shared Understanding
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Encapsulation theory and applications.pdf
Machine learning based COVID-19 study performance prediction
20250228 LYD VKU AI Blended-Learning.pptx
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Understanding_Digital_Forensics_Presentation.pptx
Network Security Unit 5.pdf for BCA BBA.
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
cuic standard and advanced reporting.pdf
“AI and Expert System Decision Support & Business Intelligence Systems”
NewMind AI Monthly Chronicles - July 2025
A Presentation on Artificial Intelligence
Mobile App Security Testing_ A Comprehensive Guide.pdf
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
Dropbox Q2 2025 Financial Results & Investor Presentation
Per capita expenditure prediction using model stacking based on satellite ima...
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx

The Logical Burrito - pattern matching, term rewriting and unification

  • 1. 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 orb@nostacktrace.com @MaximoBurrito
  • 2. 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
  • 3. Pattern Matching as a dispatch mechanism (or simple conditional) a way to express the selection criteria for which code to execute
  • 4. • 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
  • 5. Multimethods (defmulti fact identity) (defmethod fact 0 [_] 1) (defmethod fact :default [n] (* n (fact (dec n))))
  • 6. 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
  • 7. 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))
  • 8. 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)
  • 9. 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
  • 10. Pattern Matching (SML) (* SML matching at the function level*) fun fac 0 = 1 | fac n = n * fac (n - 1);
  • 11. 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 *)
  • 12. 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
  • 13. 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))  
  • 14. Limitations of core.match • No defnm to use at language level • Syntax can be ugly • Can't match non-linear patterns: [n n]
  • 15. (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)
  • 16. 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
  • 17. 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)
  • 18. 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]]]]]]
  • 19. 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]}
  • 20. 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}
  • 21. 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))))))
  • 22. 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)])
  • 23. 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
  • 24. Unification with Prolog ?- 42 = 42. true. ?- six_times_nine = 42. false. ?- enough = enough. true. Constants unify with themselves
  • 25. Unification with Prolog ?- City = austin. City = austin. ?- 7 = Number. Number = 7. uninstantiated logic variables unify with constants.
  • 26. 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
  • 27. 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
  • 28. 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
  • 29. 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.
  • 30. 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.
  • 31. Unification with Clojure • core.logic unifier has more features, more actively maintained • core.unify has the prettier API, less baggage
  • 32. 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
  • 33. core.logic unification (unifier '[dog dog]) ;; {} (unifier '[dog cat]) ;; nil (unifier '[?animal dog]) ;; {?animal dog}   (unifier '[?foo ?bar]) ;; {?foo ?bar}
  • 34. core.logic unification (unifier '[{:name bob :age 42} {:name ?X :age ?Y}]) ;; {?X bob, ?Y 42}   (unifier '[{:name bob :age 42} {:name ?X}]) ;; nil
  • 35. core.logic unification (unifier {:when {'?num numberc}} '[[?num ?animal] [:magical :unicorn]]) ;; nil   (unifier {:when {'?num numberc}} '[[?num ?animal] [42 :unicorn]]) ;; {?animal :unicorn, ?num 42}
  • 36. 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}
  • 37. (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
  • 38. (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
  • 39. Why? • Logic programming • Machine Learning / Natural language processing • Type inferencing / type checking • Theorem proving / Equation solving
  • 41. Until the next logical burrito, (run* [your-location] (conde [(== your-location :home)] [succeed]) (!= your-location :here)) Norman Richards orb@nostacktrace.com @MaximoBurrito