Skip to content

Instantly share code, notes, and snippets.

@matlux
Last active August 29, 2015 14:16
Show Gist options
  • Save matlux/21d354857baadec6009b to your computer and use it in GitHub Desktop.
Save matlux/21d354857baadec6009b to your computer and use it in GitHub Desktop.
Implementation of Church numbers and Church boolean logic in Clojure. This is a nice demonstration of how lambda calculus handles conditional logic with only on primitive (a lambda). No if statement is necessary to implement predicate and branching logic (at least when your language is lazy).
(ns ^{:doc "Playing with Church Boolean Logic."
:author "Mathieu Gauthron"}
net.matlux.church-boolean)
(def ZERO (fn [f] (fn [x] x)))
(def ONE (fn [f] (fn [x] (f x))))
(def TWO (fn [f] (fn [x] (f (f x)))))
(def AND (fn [p] (fn [q] ((p q) p) )))
(def pred (fn [n] (fn [f] (fn [x] (((n (fn [g] (fn [h] (h (g f))))) (fn [u] x) ) (fn [u] u) ) ))))
(def minus (fn [m] (fn [n] ((n pred) m))))
(def TRUE (fn [a] (fn [b] a)))
(def FALSE (fn [a] (fn [b] b)))
(def isZero (fn [n] ((n (fn [x] FALSE)) TRUE)))
(def LEQ (fn [m] (fn [n] (isZero ((minus m) n) ))))
(def EQ (fn [m] (fn [n] ((AND ((LEQ m) n)) ((LEQ n) m)))))
;; display the value of a church bolean
(defn d [b] ((b 'TRUE) 'FALSE))
;; here is series of expressions to display the combination of logical expressions
(d TRUE)
(d FALSE)
(d ((AND TRUE) TRUE))
(d ((AND TRUE) FALSE))
(d ((AND FALSE) TRUE))
(d ((AND FALSE) FALSE))
(d (isZero ZERO ))
(d (isZero ONE ))
(d (isZero TWO ))
(d ((EQ ZERO) ONE))
(d ((EQ ONE) ZERO))
(d ((EQ TWO) ZERO))
(d ((EQ ONE) ONE))
(d ((EQ ONE) TWO))
(d ((EQ TWO) ONE))
(d ((EQ TWO) TWO))
(def a TWO)
(def b TWO)
;; this if statement can be re-writen
;; (if (= a a)
;; (+ 1 1)
;; (+ 1 2))
;; into the below lambda expression. the "then" (+ 1 1) gets evaluated and returned
((((EQ a) b) (+ 1 1)) (+ 1 2))
;; here the "else" logic is evaluated and returned"
((((EQ a) ONE) (+ 1 1)) (+ 1 2))
;;However the above evaluates both then and else because clojure follows an eager evaluation model
;; in a lazy language this wouldn't be the case
;; let's try to delay the evaluation of the "then" exp and "else" exp to recreate the true branching logic
(((((EQ a) b) (fn [] (+ 1 1))) (fn [] (+ 1 2))))
;; now let's try to write a macro
(defmacro if->lambda [clause then else]
`((((if ~clause TRUE FALSE) (fn [] ~then)) (fn [] ~else))))
(if->lambda
(= 1 1)
(+ 1 1)
(+ 1 2))
;; the above macro expands into the following:
;; (macroexpand '(if->lambda (= 1 2) (+ 1 1) (+ 1 2)))
((((if (= 1 2) TRUE FALSE)
(fn [] (+ 1 1)))
(fn [] (+ 1 2))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment