diff options
author | Konrad Hinsen <konrad.hinsen@laposte.net> | 2009-01-08 09:30:54 +0000 |
---|---|---|
committer | Konrad Hinsen <konrad.hinsen@laposte.net> | 2009-01-08 09:30:54 +0000 |
commit | 081456e0ac0880450993f7d50d56609b16b1cfb6 (patch) | |
tree | 6db7213d351247fbf543c5a08dc410131c1e5546 /src/clojure | |
parent | 806accca611331f50e30f2ff65bbf75695977cee (diff) |
monads.clj: modified maybe monad, added monad transformer maybe-t, changed default value of all monad operations from nil to ::undefined
Diffstat (limited to 'src/clojure')
-rw-r--r-- | src/clojure/contrib/monads.clj | 55 | ||||
-rw-r--r-- | src/clojure/contrib/monads/examples.clj | 12 |
2 files changed, 41 insertions, 26 deletions
diff --git a/src/clojure/contrib/monads.clj b/src/clojure/contrib/monads.clj index 42abc629..f0a9ebc5 100644 --- a/src/clojure/contrib/monads.clj +++ b/src/clojure/contrib/monads.clj @@ -1,9 +1,9 @@ ;; Monads in Clojure ;; by Konrad Hinsen -;; last updated December 30, 2008 +;; last updated January 8, 2009 -;; Copyright (c) Konrad Hinsen, 2008. All rights reserved. The use +;; Copyright (c) Konrad Hinsen, 2009. All rights reserved. The use ;; and distribution terms for this software are covered by the Eclipse ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ;; which can be found in the file epl-v10.html at the root of this @@ -24,9 +24,15 @@ are written like bindings to the monad operations m-bind and m-result (required) and m-zero and m-plus (optional)." [operations] - `(let [~'m-zero nil ~'m-plus nil ~@operations] - {:m-result ~'m-result :m-bind ~'m-bind - :m-zero ~'m-zero :m-plus ~'m-plus})) + `(let [~'m-bind ::undefined + ~'m-result ::undefined + ~'m-zero ::undefined + ~'m-plus ::undefined + ~@operations] + {:m-result ~'m-result + :m-bind ~'m-bind + :m-zero ~'m-zero + :m-plus ~'m-plus})) (defmacro defmonad "Define a named monad by defining the monad operations. The definitions @@ -53,7 +59,7 @@ [mexpr step] (let [[bform expr] step] (if (identical? bform :when) - (list 'm-bind `(if ~expr (~'m-result nil) ~'m-zero) + (list 'm-bind `(if ~expr (~'m-result ::any) ~'m-zero) (list 'fn ['_] mexpr)) (list 'm-bind expr (list 'fn [bform] mexpr))))) @@ -182,18 +188,14 @@ ; Maybe monad (defmonad maybe "Monad describing computations with possible failures. Failure is - represented by an empty vector, success by a vector with a single - element, the resulting value." - [m-zero [] - m-result (fn m-result-maybe [v] - [v]) + represented by nil, any other value is considered valid. As soon as + a step returns nil, the whole computation will yield nil as well." + [m-zero nil + m-result (fn m-result-maybe [v] v) m-bind (fn m-bind-maybe [mv f] - (if (= mv m-zero) - m-zero - (f (first mv)))) + (if (nil? mv) nil (f mv))) m-plus (fn m-plus-maybe [& mvs] - (let [first-valid (first (drop-while empty? mvs))] - (if (nil? first-valid) m-zero first-valid))) + (first (drop-while nil? mvs))) ]) ; Sequence monad (called "list monad" in Haskell) @@ -230,3 +232,24 @@ (defn fetch-state [] (update-state identity)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Monad transformers +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defn maybe-t + "Monad transformer that transforms a monad m into a monad in which + the base values can be invalid (represented by nil)." + [m] + (monad [m-result (with-monad m + m-result) + m-bind (with-monad m + (fn m-bind-maybe-t [mv f] + (m-bind mv + (fn [x] + (if (nil? x) (m-result nil) (f x)))))) + m-zero (with-monad m m-zero) + m-plus (with-monad m m-plus)])) diff --git a/src/clojure/contrib/monads/examples.clj b/src/clojure/contrib/monads/examples.clj index 89515c49..8ddf91be 100644 --- a/src/clojure/contrib/monads/examples.clj +++ b/src/clojure/contrib/monads/examples.clj @@ -93,16 +93,8 @@ ; Division is special for two reasons: we can't call it m/ because that's ; not a legal Clojure symbol, and we want it to fail if a division by zero -; is attempted. It can be defined explictly: -(with-monad maybe - (defn safe-div [x y] - (cond (= m-zero x) m-zero - (= m-zero y) m-zero - (= (first y) 0) m-zero - :else (m-result (/ (first x) (first y)))))) - -; It can also be defined as a monad comprehension that performs the test -; in a :when clause: +; is attempted. It is best defined by a monad comprehension with a +; :when clause: (defn safe-div [x y] (domonad maybe [a x |