Let's say we want to computer the area of some Shape
types like Square
and Circle
We may have some function called sum-areas
that takes a list of Shape
, calls area on each of them, and sums them up. We don't have access to the original source, but want the ability to add new shapes.
(defprotocol Shape
(area [x]))
(defrecord Rectangle [length width]
Shape
(area [r] (* length width)))
(defrecord Circle
Shape
(area [c] (* PI (Math/pow radius 2))))
(s/def :shape/type keyword?)
(s/def :shape/length pos-int?)
(s/def :shape/width pos-int?)
(s/def :shape/radius pos-int?)
(defmulti shape-type :shape/type)
(s/def :shape/shape (s/multi-spec shape-type :shape/type))
(defmethod shape-type :shape/rect [_]
(s/keys :req [:shape/length :shape/width]))
(defmethod shape-type :shape/circle [_]
(s/keys :req [:shape/radius]))
(defmulti area :shape/shape)
(defmethod area :shape/rect
[{:keys [length width]}]
(* length width))
(def PI 3.14340)
(defmethod area :shape/circle
[{:keys [radius]}]
(* PI (Math/pow radius 2)))
(defprotocol Solid
(volume [s]))
(defrecord Cube [length width height]
Shape
(area [c] (+ (* 2 length width) (* 2 length height ) (* 2 width height)))
Solid
(volume [c] (* length width height)))
(s/def :solid/height pos-int?)
(defmethod shape-type :solid/cube [_]
(s/keys :req [:shape/length :shape/width :solid/height]))
(defmethod area :shape/cube
[{:keys [length width height]}]
(+ (* 2 length width) (* 2 length height ) (* 2 width height)))
(defmulti solid-type :solid/type)
(s/def :solid/solid (s/multi-spec shape-type :solid/type))
(defmethod area :solid/cube
[{:keys [length width height]}]
(+ (* 2 length width) (* 2 length height) (* 2 width height)))
(defmulti volume :solid/type)
(defmethod volume :solid/cube
[{:keys [length width height]}]
(* length width height))
For the circle defrecord you presumably you meant:
Everything else compiles!