Skip to content

Instantly share code, notes, and snippets.

@christianromney
Last active August 29, 2015 13:55
Show Gist options
  • Save christianromney/8693783 to your computer and use it in GitHub Desktop.
Save christianromney/8693783 to your computer and use it in GitHub Desktop.
An example of how to define abstractions in Clojure
;; BinOp ::= [Symbol Operand Operand]
;; Operand ::= Number | BinaryOperation
(defprotocol Numerical
"A thing which has a numerical value"
(value [this]))
(defprotocol PrintableMathExpression
"A mathematical expression which can be printed
using infix or prefix notation"
(prefix [this])
(infix [this]))
(defrecord BinOp
[operator rand1 rand2]
Numerical
(value [this] ((eval (:operator this))
(value (:rand1 this))
(value (:rand2 this))))
PrintableMathExpression
(prefix [this]
(list (:operator this)
(prefix (:rand1 this))
(prefix (:rand2 this))))
(infix [this]
(list (infix (:rand1 this))
(:operator this)
(infix (:rand2 this)))))
(defn binop
{:pre #(and (symbol? %1)
(extends? Numerical %2)
(extends? Numerical %3))}
[rator rand1 rand2]
(->BinOp rator rand1 rand2))
(extend-type Number
Numerical
(value [this] this)
PrintableMathExpression
(prefix [this] this)
(infix [this] this))
;; Test what we have wrought!
(def expression (binop '+
(binop '* 7 8)
(binop '/
100
(binop '* 2 2))))
(prefix expression)
(infix expression)
(value expression)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment