Hi,

Am 26.05.2009 um 14:15 schrieb Rich Hickey:

Yes - keep your functions out of your data. If you are used to
engine.getMove(position) it becomes:

(get-move engine position)

If you want polymorphism you can make get-move a multimethod. If the
'engine' concept is only about code (e.g. has no data of its own, just
specifies a protocol), you can simply use names for engines in your
multimethods:

(get-move :minmax-engine position)
(get-move :greedy-engine position)

as Rich said: multimethods to the rescue.

You could define a namespace giving the interface of an engine. This
consists of the method definitions and maybe some default implementations.

(ns car.engine)

(defmulti start
  "Start the engine."
  type)

(defmulti refuel
  "Refuel the tank of the engine."
  (fn refuel-dispatch [e _] (type e)))

(defmethod refuel :default
  [e amount]
  (swap! (:tank e) + amount))

(defmulti explode
  "Explode the engine."
  type)

(defmethod explode :default
  [e]
  "BOOOM!")

This basically looks similar to an abstract class in Java. Now we have
to provide some concrete implementation.

(ns car.engine.otto
  (:require
    [car.engine :as engine]))

(let [type-info {:type ::Otto}]
  (defn make-engine
    [initial-fuel]
    (with-meta {:tank (atom initial-fuel)} type-info)))

(defmethod engine/start ::Otto
  [e]
  "VROOOOM!")

And another one:

(ns car.engine.diesel
  (:require
    [car.engine :as engine]))

(let [type-info {:type ::Diesel}]
  (defn make-engine
    [initial-fuel]
    (with-meta {:tank (atom initial-fuel)} type-info)))

(defmethod engine/start ::Diesel
  [e]
  "TACKTACKTACKTACK!")

(defmethod engine/explode ::Diesel
  [e]
  "POOOOOOOF!")

Now we use our different implementations.

(ns car.sportscar
  (:require
    [car.engine :as engine]
    [car.engine.otto :as otto]))

(defn make-sportscar
  []
  {:engine (otto/make-engine)})

(defn do-drive
  [car]
  (engine/start (:engine car))
  (accelerate car)
  (brake car)
  (engine/refuel (:engine car) 100)
  ...)

Or the diesel one....

(ns car.truck
  (:require
    [car.engine :as engine]
    [car.engine.diesel :as diesel]))

(defn make-truck
  []
  {:engine (diesel/make-engine)})

....

You get the idea...

Although this went a bit away from the initial chess example,
it should give an idea how the original problem could be solved.
A more real life example is my experimental monad library
based on multimethods (http://bitbucket.org/kotarak/monad).

Hope this helps.

Sincerely
Meikel

Attachment: smime.p7s
Description: S/MIME cryptographic signature

Reply via email to