Commits

Meikel Brandmeyer committed f6f5b7e

Use metadata to carry monad information

* monad.clj (defmonad): new function
(bind): modified to use ::monad key in meta-data
(monad-structure): obsolete => removed

Comments (0)

Files changed (1)

src/de/kotka/monad.clj

 
 (clojure.core/ns de.kotka.monad)
 
-(def
-  #^{:doc
-  "Description
-  -----------
-
-  `monad-structure` defines the basic structure of the monad supporting
-  structure. The :monad key is the dispatch value for the `bind` multimethod.
-  Whatever else is contained in the structure is completely up to the actual
-  implementation and will not be touched by the functions of the monad library."}
-  monad-structure
-  (create-struct :monad))
-
-(defn make-monad
-  "Synopsis
-  --------
-
-  (make-monad monad-type key value ...)
-
-  Description
-  -----------
-
-  `make-monad` creates a new monad structure and associates the :monad key
-  with given monad-type. What the monad-type actually is, is up to the caller.
-  This value will be used for dispatching in the `bind` multimethod.
-
-  Any further key-value pairs will be associated with the map."
-  [monad-type & kvs]
-  (apply struct-map monad-structure :monad monad-type kvs))
+(defn return
+  "Bless an object with the given monad type."
+  [t m]
+  (with-meta m (assoc (meta m) ::monad t)))
 
 (defmulti
   #^{:doc
-  "Synopsis
-  --------
-
-  (bind monad (fn [result] ...)) : Monad a -> (a -> b)-> Monad b
-
-  Description
-  -----------
-
-  `bind` makes the value of the given monad available to a function.
+  "bind makes the value of the given monad available to a function.
   The function may act on the value, but it must return another monad.
-  (Although this cannot be enforced in Clojure."}
-  bind (fn [m f] (:monad m)))
+  Although this cannot be enforced in Clojure."}
+  bind (fn [m _] (-> m meta ::monad)))
 
 (defmacro let-bind
-  "Synopsis
-  --------
-
-  (let [var1 monad1
-        ...
-        varN monadN]
-    body ...)
-
-  Description
-  -----------
-
-  `let-bind` binds the result of the given monads to the given variables
-  and executes the body in an implicit `do` block. How this done exactly
-  depends on the actual monad. The `let-bind` body should again return a
+  "let-bind binds the result of the given monads to the given variables
+  and executes the body in an implicit do block. How this done exactly
+  depends on the actual monad. The let-bind body should again return a
   monad."
   [clauses & body]
-  (let [[var monad & clauses] clauses]
+  (let [[v monad & clauses] clauses]
     (if (nil? clauses)
-      `(bind ~monad (fn [~var] ~@body))
-      `(bind ~monad (fn [~var] (let-bind ~clauses ~@body))))))
+      `(bind ~monad (fn [~v] ~@body))
+      `(bind ~monad (fn [~v] (let-bind ~clauses ~@body))))))