From e0073e77a4e8cedf794088fce29671f6ca421f62 Mon Sep 17 00:00:00 2001 From: Roman Gonzalez Date: Sun, 1 Jan 2012 10:15:20 -0800 Subject: [PATCH 1/8] Adding basic support for if-then --- src/main/clojure/clojure/algo/monads.clj | 130 ++++++++++++++++--------- src/test/clojure/clojure/algo/test_monads.clj | 28 +++++- 2 files changed, 112 insertions(+), 46 deletions(-) diff --git a/src/main/clojure/clojure/algo/monads.clj b/src/main/clojure/clojure/algo/monads.clj index 775d633..f25cb22 100644 --- a/src/main/clojure/clojure/algo/monads.clj +++ b/src/main/clojure/clojure/algo/monads.clj @@ -20,7 +20,8 @@ as macros for defining and using monads and useful monadic functions."} clojure.algo.monads - (:require [clojure.set]) + (:require [clojure.set] + [clojure.pprint :as pp]) (:use [clojure.tools.macro :only (with-symbol-macros defsymbolmacro name-with-attributes)])) @@ -46,16 +47,16 @@ :m-plus ~'m-plus})) (defmacro defmonad - "Define a named monad by defining the monad operations. The definitions - are written like bindings to the monad operations m-bind and - m-result (required) and m-zero and m-plus (optional)." + "Define a named monad by defining the monad operations. The definitions + are written like bindings to the monad operations m-bind and + m-result (required) and m-zero and m-plus (optional)." - ([name doc-string operations] - (let [doc-name (with-meta name {:doc doc-string})] - `(defmonad ~doc-name ~operations))) + ([name doc-string operations] + (let [doc-name (with-meta name {:doc doc-string})] + `(defmonad ~doc-name ~operations))) - ([name operations] - `(def ~name (monad ~operations)))) + ([name operations] + `(def ~name (monad ~operations)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -64,14 +65,49 @@ ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defn- add-monad-step +(defn ensure-items [n steps] + (take n (concat steps (repeat nil)))) + +(defn each4-steps [steps] + (let [n (count steps)] + (map vector (ensure-items n steps) + (ensure-items n (rest steps)) + (ensure-items n (rest (rest steps))) + (ensure-items n (rest (rest (rest steps))))))) + +(defn add-monad-step "Add a monad comprehension step before the already transformed monad comprehension expression mexpr." - [mexpr step] - (let [[bform expr] step] - (cond (identical? bform :when) `(if ~expr ~mexpr ~'m-zero) - (identical? bform :let) `(let ~expr ~mexpr) - :else (list 'm-bind expr (list 'fn [bform] mexpr))))) + [mexpr steps] + (let [[step1 step2 step3 step4] steps + [bform expr] step1 + [bform2 expr2] step2 + [bform3 expr3] step3 + [bform4 expr4] step4] + (cond + (nil? step1) ~mexpr + (identical? bform :when) `(if ~expr ~mexpr ~'m-zero) + (identical? bform :let) `(let ~expr ~mexpr) + (and (identical? bform :else) + (identical? bform2 :then) + (identical? bform3 :if)) + (let [x + (list 'm-bind expr4 (list 'fn [bform4] + `(if ~expr3 + ~(reduce add-monad-step + mexpr + (each4-steps (reverse (partition 2 expr2)))) + ~(reduce add-monad-step + mexpr + (each4-steps (reverse (partition 2 expr)))))))] + (println (pp/pprint x)) + x) + (identical? bform :else) + (throw (Exception. "invalid :if without :then and :else")) + (identical? bform :then) mexpr + (identical? bform :if) mexpr + :else + (list 'm-bind expr (list 'fn [bform] mexpr))))) (defn- monad-expr "Transforms a monad comprehension, consisting of a list of steps @@ -82,46 +118,52 @@ [steps expr] (when (odd? (count steps)) (throw (Exception. "Odd number of elements in monad comprehension steps"))) - (let [rsteps (reverse (partition 2 steps)) + + (let [rsteps (reverse (partition 2 steps)) [lr ls] (first rsteps)] + + (println "PAY ATTENTION") + (println (pp/pprint rsteps)) (if (= lr expr) ; Optimization: if the result expression is equal to the result ; of the last computation step, we can eliminate an m-bind to ; m-result. (reduce add-monad-step - ls - (rest rsteps)) + ls + (each4-steps (rest rsteps))) ; The general case. - (reduce add-monad-step - (list 'm-result expr) - rsteps)))) + (let [result (reduce add-monad-step + (list 'm-result expr) + (each4-steps rsteps))] + (println (pp/pprint result)) + result)))) (defmacro with-monad - "Evaluates an expression after replacing the keywords defining the - monad operations by the functions associated with these keywords - in the monad definition given by name." - [monad & exprs] - `(let [name# ~monad - ~'m-bind (:m-bind name#) - ~'m-result (:m-result name#) - ~'m-zero (:m-zero name#) - ~'m-plus (:m-plus name#)] - (with-symbol-macros ~@exprs))) + "Evaluates an expression after replacing the keywords defining the + monad operations by the functions associated with these keywords + in the monad definition given by name." + [monad & exprs] + `(let [name# ~monad + ~'m-bind (:m-bind name#) + ~'m-result (:m-result name#) + ~'m-zero (:m-zero name#) + ~'m-plus (:m-plus name#)] + (with-symbol-macros ~@exprs))) (defmacro domonad - "Monad comprehension. Takes the name of a monad, a vector of steps - given as binding-form/monadic-expression pairs, and a result value - specified by expr. The monadic-expression terms can use the binding - variables of the previous steps. - If the monad contains a definition of m-zero, the step list can also - contain conditions of the form :when p, where the predicate p can - contain the binding variables from all previous steps. - A clause of the form :let [binding-form expr ...], where the bindings - are given as a vector as for the use in let, establishes additional - bindings that can be used in the following steps." - ([steps expr] + "Monad comprehension. Takes the name of a monad, a vector of steps + given as binding-form/monadic-expression pairs, and a result value + specified by expr. The monadic-expression terms can use the binding + variables of the previous steps. + If the monad contains a definition of m-zero, the step list can also + contain conditions of the form :when p, where the predicate p can + contain the binding variables from all previous steps. + A clause of the form :let [binding-form expr ...], where the bindings + are given as a vector as for the use in let, establishes additional + bindings that can be used in the following steps." + ([steps expr] (monad-expr steps expr)) - ([name steps expr] + ([name steps expr] (let [mexpr (monad-expr steps expr)] `(with-monad ~name ~mexpr)))) @@ -514,7 +556,7 @@ :m-zero (with-monad ~base ~'m-zero) :m-plus (with-monad ~base ~'m-plus)) combined-monad#))) - + (defn maybe-t "Monad transformer that transforms a monad m into a monad in which the base values can be invalid (represented by nothing, which defaults diff --git a/src/test/clojure/clojure/algo/test_monads.clj b/src/test/clojure/clojure/algo/test_monads.clj index e5edfdd..d5cd029 100644 --- a/src/test/clojure/clojure/algo/test_monads.clj +++ b/src/test/clojure/clojure/algo/test_monads.clj @@ -11,8 +11,32 @@ (ns clojure.algo.test-monads (:use [clojure.test :only (deftest is are run-tests)] [clojure.algo.monads - :only (with-monad domonad m-lift m-seq m-chain writer-m write - sequence-m maybe-m state-m maybe-t sequence-t)])) + :only (with-monad domonad m-lift m-seq m-chain writer-m write + sequence-m maybe-m state-m maybe-t sequence-t)])) + + +(deftest domonad-if-then + (let [monad-value (domonad maybe-m + [ a 5 + :if (= a 5) + :then [ + b 6] + :else [ + b nil]] + [a b])] + (is (= monad-value [5 6])))) + + +(deftest domonad-if-else + (let [monad-value (domonad maybe-m + [ a 5 + :if (= a 1) + :then [ + b 6] + :else [ + b nil]] + [a b])] + (is (= monad-value nil)))) (deftest sequence-monad (with-monad sequence-m -- 1.7.6 From d05ca4e073a41f5d4bb3d28db6741ee81665c16f Mon Sep 17 00:00:00 2001 From: Roman Gonzalez Date: Sun, 1 Jan 2012 10:27:58 -0800 Subject: [PATCH 2/8] Remove extra code that is not needed for if-then support. * Also remove "print traces" of data structures created by the macro * Making the add-monad-step function private again --- src/main/clojure/clojure/algo/monads.clj | 63 ++++++++++++++--------------- 1 files changed, 30 insertions(+), 33 deletions(-) diff --git a/src/main/clojure/clojure/algo/monads.clj b/src/main/clojure/clojure/algo/monads.clj index f25cb22..3bcbb4b 100644 --- a/src/main/clojure/clojure/algo/monads.clj +++ b/src/main/clojure/clojure/algo/monads.clj @@ -20,8 +20,7 @@ as macros for defining and using monads and useful monadic functions."} clojure.algo.monads - (:require [clojure.set] - [clojure.pprint :as pp]) + (:require [clojure.set]) (:use [clojure.tools.macro :only (with-symbol-macros defsymbolmacro name-with-attributes)])) @@ -68,14 +67,13 @@ (defn ensure-items [n steps] (take n (concat steps (repeat nil)))) -(defn each4-steps [steps] +(defn each3-steps [steps] (let [n (count steps)] - (map vector (ensure-items n steps) - (ensure-items n (rest steps)) - (ensure-items n (rest (rest steps))) - (ensure-items n (rest (rest (rest steps))))))) + (map vector (ensure-items n steps) + (ensure-items n (rest steps)) + (ensure-items n (rest (rest steps)))))) -(defn add-monad-step +(defn- add-monad-step "Add a monad comprehension step before the already transformed monad comprehension expression mexpr." [mexpr steps] @@ -83,30 +81,34 @@ [bform expr] step1 [bform2 expr2] step2 [bform3 expr3] step3 - [bform4 expr4] step4] - (cond - (nil? step1) ~mexpr + [bform4 expr4] step4 + prepare-steps #(->> % (partition 2) reverse each3-steps)] + (cond (identical? bform :when) `(if ~expr ~mexpr ~'m-zero) (identical? bform :let) `(let ~expr ~mexpr) + ;; conditional if-then-else support + ; ignore step vector that start with nil + (nil? step1) mexpr + ; ignore :then step (processed on the :else step) + (identical? bform :then) mexpr + ; ignore :if step (processed on the :else step) + (identical? bform :if) mexpr + ; process :if statement starting from the :else (and (identical? bform :else) (identical? bform2 :then) (identical? bform3 :if)) - (let [x - (list 'm-bind expr4 (list 'fn [bform4] - `(if ~expr3 - ~(reduce add-monad-step - mexpr - (each4-steps (reverse (partition 2 expr2)))) - ~(reduce add-monad-step - mexpr - (each4-steps (reverse (partition 2 expr)))))))] - (println (pp/pprint x)) - x) + `(if ~expr3 + ~(reduce add-monad-step + mexpr + (prepare-steps expr2)) + ~(reduce add-monad-step + mexpr + (prepare-steps expr))) + ; if we are at this case and we didn't enter in the + ; previous one, we have a broken build (identical? bform :else) (throw (Exception. "invalid :if without :then and :else")) - (identical? bform :then) mexpr - (identical? bform :if) mexpr - :else + :else (list 'm-bind expr (list 'fn [bform] mexpr))))) (defn- monad-expr @@ -121,22 +123,17 @@ (let [rsteps (reverse (partition 2 steps)) [lr ls] (first rsteps)] - - (println "PAY ATTENTION") - (println (pp/pprint rsteps)) (if (= lr expr) ; Optimization: if the result expression is equal to the result ; of the last computation step, we can eliminate an m-bind to ; m-result. (reduce add-monad-step ls - (each4-steps (rest rsteps))) + (each3-steps (rest rsteps))) ; The general case. - (let [result (reduce add-monad-step + (reduce add-monad-step (list 'm-result expr) - (each4-steps rsteps))] - (println (pp/pprint result)) - result)))) + (each3-steps rsteps))))) (defmacro with-monad "Evaluates an expression after replacing the keywords defining the -- 1.7.6 From 1af92195c8bff1f7a8bb84d30426c90e83053e89 Mon Sep 17 00:00:00 2001 From: Roman Gonzalez Date: Sun, 1 Jan 2012 11:01:42 -0800 Subject: [PATCH 3/8] Clean the code a little bit and add documentation. * Documentation for if-then-else statement support functions (plus helpers). * Extended the unit tests for if-then-else statement support. * Refactored the code a bit to reuse functions. --- src/main/clojure/clojure/algo/monads.clj | 68 +++++++++++++----------- src/test/clojure/clojure/algo/test_monads.clj | 10 +++- 2 files changed, 44 insertions(+), 34 deletions(-) diff --git a/src/main/clojure/clojure/algo/monads.clj b/src/main/clojure/clojure/algo/monads.clj index 3bcbb4b..1516190 100644 --- a/src/main/clojure/clojure/algo/monads.clj +++ b/src/main/clojure/clojure/algo/monads.clj @@ -64,50 +64,56 @@ ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defn ensure-items [n steps] +(defn- ensure-items [n steps] + "Ensures there are at least n elements on a list, will fill up with nil + values when list is not big enough." (take n (concat steps (repeat nil)))) -(defn each3-steps [steps] +(defn- each3-steps [steps] + "Transforms a list in a list of triples following the form: + [a b c] => [[a b c] [b c nil] [c nil nil]]." (let [n (count steps)] (map vector (ensure-items n steps) (ensure-items n (rest steps)) (ensure-items n (rest (rest steps)))))) +(def prepare-monadic-steps + #(->> % (partition 2) reverse each3-steps)) + +(defn- if-then-else-statement + "Process an if-then-else step when adding a new monadic step to the mexrp." + [[[_ else-mexpr] + [then-bform then-mexpr] + [if-bform if-conditional]] mexpr continuation] + (cond + (and (identical? then-bform :then) + (identical? if-bform :if)) + `(if ~if-conditional + ~(reduce continuation + mexpr + (prepare-monadic-steps then-mexpr)) + ~(reduce continuation + mexpr + (prepare-monadic-steps else-mexpr))) + :else + (throw (Exception. "invalid :if without :then and :else")))) + + (defn- add-monad-step "Add a monad comprehension step before the already transformed monad comprehension expression mexpr." [mexpr steps] - (let [[step1 step2 step3 step4] steps - [bform expr] step1 - [bform2 expr2] step2 - [bform3 expr3] step3 - [bform4 expr4] step4 - prepare-steps #(->> % (partition 2) reverse each3-steps)] + (let [[[bform expr :as step] & _] steps] (cond (identical? bform :when) `(if ~expr ~mexpr ~'m-zero) (identical? bform :let) `(let ~expr ~mexpr) - ;; conditional if-then-else support - ; ignore step vector that start with nil - (nil? step1) mexpr - ; ignore :then step (processed on the :else step) + (nil? step) mexpr (identical? bform :then) mexpr - ; ignore :if step (processed on the :else step) + ; ^ ignore :then step (processed on the :else step) (identical? bform :if) mexpr - ; process :if statement starting from the :else - (and (identical? bform :else) - (identical? bform2 :then) - (identical? bform3 :if)) - `(if ~expr3 - ~(reduce add-monad-step - mexpr - (prepare-steps expr2)) - ~(reduce add-monad-step - mexpr - (prepare-steps expr))) - ; if we are at this case and we didn't enter in the - ; previous one, we have a broken build + ; ^ ignore :if step (processed on the :else step) (identical? bform :else) - (throw (Exception. "invalid :if without :then and :else")) + (if-then-else-statement steps mexpr add-monad-step) :else (list 'm-bind expr (list 'fn [bform] mexpr))))) @@ -121,19 +127,19 @@ (when (odd? (count steps)) (throw (Exception. "Odd number of elements in monad comprehension steps"))) - (let [rsteps (reverse (partition 2 steps)) - [lr ls] (first rsteps)] + (let [rsteps (prepare-monadic-steps steps) + [[lr ls] & _] (first rsteps)] (if (= lr expr) ; Optimization: if the result expression is equal to the result ; of the last computation step, we can eliminate an m-bind to ; m-result. (reduce add-monad-step ls - (each3-steps (rest rsteps))) + (rest rsteps)) ; The general case. (reduce add-monad-step (list 'm-result expr) - (each3-steps rsteps))))) + rsteps)))) (defmacro with-monad "Evaluates an expression after replacing the keywords defining the diff --git a/src/test/clojure/clojure/algo/test_monads.clj b/src/test/clojure/clojure/algo/test_monads.clj index d5cd029..bfcbc1a 100644 --- a/src/test/clojure/clojure/algo/test_monads.clj +++ b/src/test/clojure/clojure/algo/test_monads.clj @@ -18,11 +18,14 @@ (deftest domonad-if-then (let [monad-value (domonad maybe-m [ a 5 - :if (= a 5) + :let [c 7] + :if (and (= a 5) (= c 7)) :then [ - b 6] + b 6 + ] :else [ - b nil]] + b nil + ]] [a b])] (is (= monad-value [5 6])))) @@ -30,6 +33,7 @@ (deftest domonad-if-else (let [monad-value (domonad maybe-m [ a 5 + :when (= a 5) :if (= a 1) :then [ b 6] -- 1.7.6 From 22336cb37d9d2cb55cc712743a206dd4ffd7736d Mon Sep 17 00:00:00 2001 From: Roman Gonzalez Date: Sun, 1 Jan 2012 11:03:36 -0800 Subject: [PATCH 4/8] Adding myself to the developer list on the pom.xml file --- pom.xml | 25 ++++++++++++++++--------- 1 files changed, 16 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index 614d514..9602e15 100644 --- a/pom.xml +++ b/pom.xml @@ -1,21 +1,28 @@ - - 4.0.0 + + algo.monads 0.1.1-SNAPSHOT - ${artifactId} - - - org.clojure - pom.contrib - 0.0.25 - + ${project.artifactId} + 4.0.0 Konrad Hinsen + + Roman Gonzalez + romanandreg@gmail.com + + + org.clojure + pom.contrib + 0.0.25 + + org.clojure -- 1.7.6 From 1849b42ec0231ffb743d1d1797a6dcc72a469ab9 Mon Sep 17 00:00:00 2001 From: Roman Gonzalez Date: Sun, 1 Jan 2012 11:11:28 -0800 Subject: [PATCH 5/8] Removing useless check on the add-monad-step function. --- src/main/clojure/clojure/algo/monads.clj | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/src/main/clojure/clojure/algo/monads.clj b/src/main/clojure/clojure/algo/monads.clj index 1516190..7b3d669 100644 --- a/src/main/clojure/clojure/algo/monads.clj +++ b/src/main/clojure/clojure/algo/monads.clj @@ -107,7 +107,6 @@ (cond (identical? bform :when) `(if ~expr ~mexpr ~'m-zero) (identical? bform :let) `(let ~expr ~mexpr) - (nil? step) mexpr (identical? bform :then) mexpr ; ^ ignore :then step (processed on the :else step) (identical? bform :if) mexpr -- 1.7.6 From 60d07d8c29647969c6d18aa846ece1ec4c62eb9d Mon Sep 17 00:00:00 2001 From: Roman Gonzalez Date: Sun, 1 Jan 2012 11:12:50 -0800 Subject: [PATCH 6/8] Making the prepare-monadic-steps utility function private. --- src/main/clojure/clojure/algo/monads.clj | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/main/clojure/clojure/algo/monads.clj b/src/main/clojure/clojure/algo/monads.clj index 7b3d669..37aeaf4 100644 --- a/src/main/clojure/clojure/algo/monads.clj +++ b/src/main/clojure/clojure/algo/monads.clj @@ -77,7 +77,7 @@ (ensure-items n (rest steps)) (ensure-items n (rest (rest steps)))))) -(def prepare-monadic-steps +(def ^:private prepare-monadic-steps #(->> % (partition 2) reverse each3-steps)) (defn- if-then-else-statement -- 1.7.6 From b15850e72e2285e0c42ad11bbea9d9997b1b8698 Mon Sep 17 00:00:00 2001 From: Roman Gonzalez Date: Sat, 21 Jan 2012 20:27:50 -0800 Subject: [PATCH 7/8] Removing whitespaces from test_monads --- src/test/clojure/clojure/algo/test_monads.clj | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/clojure/clojure/algo/test_monads.clj b/src/test/clojure/clojure/algo/test_monads.clj index bfcbc1a..5f29d22 100644 --- a/src/test/clojure/clojure/algo/test_monads.clj +++ b/src/test/clojure/clojure/algo/test_monads.clj @@ -18,7 +18,7 @@ (deftest domonad-if-then (let [monad-value (domonad maybe-m [ a 5 - :let [c 7] + :let [c 7] :if (and (= a 5) (= c 7)) :then [ b 6 @@ -33,7 +33,7 @@ (deftest domonad-if-else (let [monad-value (domonad maybe-m [ a 5 - :when (= a 5) + :when (= a 5) :if (= a 1) :then [ b 6] -- 1.7.6 From 1c42a37320c4c9dad860da0aeb7cae0806d96a00 Mon Sep 17 00:00:00 2001 From: Roman Gonzalez Date: Sat, 21 Jan 2012 20:34:31 -0800 Subject: [PATCH 8/8] Add :cond statement for domacro definitions Now besides :if-then-else statements one can have also :cond to check different boolean statements, it will work the same way as the cond macro. Example: (domonad maybe-m [value some-monadic-value :cond [(= (mod value 2) 0) [result "the value is pair"] :else [result "the value is not pair"]]] result) --- src/main/clojure/clojure/algo/monads.clj | 23 +++++++++++++++++++++-- src/test/clojure/clojure/algo/test_monads.clj | 18 ++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/main/clojure/clojure/algo/monads.clj b/src/main/clojure/clojure/algo/monads.clj index 37aeaf4..15586fd 100644 --- a/src/main/clojure/clojure/algo/monads.clj +++ b/src/main/clojure/clojure/algo/monads.clj @@ -81,8 +81,9 @@ #(->> % (partition 2) reverse each3-steps)) (defn- if-then-else-statement - "Process an if-then-else step when adding a new monadic step to the mexrp." - [[[_ else-mexpr] + "Process an :if :then :else steps when adding a new + monadic step to the mexrp." + [[[_ else-mexpr] [then-bform then-mexpr] [if-bform if-conditional]] mexpr continuation] (cond @@ -98,6 +99,23 @@ :else (throw (Exception. "invalid :if without :then and :else")))) +(defn- merge-cond-branches [cond-branches] + (let [merger (fn [result cond-branch] + (-> result + (conj (first cond-branch)) + (conj (second cond-branch))))] + (reduce merger [] cond-branches))) + +(defn cond-statement + "Process a :cond steps when adding a new monadic step to the mexrp." + [expr mexpr continuation] + (let [cond-sexps (partition 2 expr) + result (for [[cond-sexp monadic-sexp] cond-sexps] + (list cond-sexp + (reduce continuation + mexpr + (prepare-monadic-steps monadic-sexp))))] + `(cond ~@(merge-cond-branches result)))) (defn- add-monad-step "Add a monad comprehension step before the already transformed @@ -107,6 +125,7 @@ (cond (identical? bform :when) `(if ~expr ~mexpr ~'m-zero) (identical? bform :let) `(let ~expr ~mexpr) + (identical? bform :cond) (cond-statement expr mexpr add-monad-step) (identical? bform :then) mexpr ; ^ ignore :then step (processed on the :else step) (identical? bform :if) mexpr diff --git a/src/test/clojure/clojure/algo/test_monads.clj b/src/test/clojure/clojure/algo/test_monads.clj index 5f29d22..b9b3e23 100644 --- a/src/test/clojure/clojure/algo/test_monads.clj +++ b/src/test/clojure/clojure/algo/test_monads.clj @@ -42,6 +42,24 @@ [a b])] (is (= monad-value nil)))) +(deftest domonad-cond + (let [monad-value (domonad maybe-m + [ a 5 + :when (= a 5) + :cond + [(< a 1) + [result "less than one"] + (< a 3) + [result "less than three"] + (< a 6) + [result "less than six"] + :else + [result "arbitrary number"]] + b 7 + :let [some-val 12345]] + [result b some-val])] + (is (= monad-value ["less than six" 7 12345])))) + (deftest sequence-monad (with-monad sequence-m (are [a b] (= a b) -- 1.7.6