我需要帮助写一个'sequence-maybe-m'(一个monad,它结合了一个序列monad和一个monad的行为)。
规则应该是:
(domonad sequence-maybe-m [a [1 2 3] b [1 2 3]] (+ a b)) ;; => (2 3 4 3 4 5 4 5 6) (domonad sequence-maybe-m [a [1 2 3] b nil] (+ a b)) ;; => nil (domonad sequence-maybe-m [a [1 2 3] b (range a)] (+ a b)) ;; => (1 2 3 3 4 5) same as 'for' (domonad sequence-maybe-m [a [1 2 3] b [1 nil 3]] (+ a b)) ;; => nil
如果它与clojure.algo.monads库兼容,那将是一个奖励:
(defmonad sequence-maybe-m
[m-result <...>
m-bind <...>
m-zero <...>
m-plus <...>
])
其中&lt; ...&gt;是功能。
答案 0 :(得分:5)
; helper function for nil-ness
(defn nil-or-has-nil? [xs] (or (nil? xs) (some nil? xs)))
; the actual monad
(defmonad sequence-maybe-m
[m-result (fn [v] [v]) ; lift any value into a sequence
m-bind (fn [mv f] ; given a monadic value and a function
(if (nil-or-has-nil? mv) ; if any nil,
nil ; result in nil
(let [result (map f mv)] ; map over valid input seq
(if (some nil? result) ; if any nils result
nil ; return nil
(apply concat result))))) ; else flatten resulting seq
m-plus (fn [& mvs] ; given a sequence of mvs
(if (some nil-or-has-nil? mvs) ; if any nil,
nil ; result in nil
(apply concat mvs))) ; otherwise, join seqs
m-zero []]) ; empty seq is identity for concatenation
真正值得关注的唯一一点是nil-or-has-nil?
中的第二个m-bind
。第一个是预期的 - 通过一个monadic值,m-bind
必须确定它是nil
- ish并且应该立即产生nil
。第二个检查计算结果 - 如果失败(产生任何nil
),那么整体结果必须是nil
(而不是由(apply concat [nil nil ...])
产生的空列表。 )。
答案 1 :(得分:3)
domonad
的输出必须是monadic值,在sequence-m
的情况下,这意味着它必须是序列。要求nil
的输出中断,而你没有monad。
你可能正在寻找的是使用monadic变换器直接在sequence-monad中添加“maybe”,这很容易做到并在这里描述:http://clojuredocs.org/clojure_contrib/1.2.0/clojure.contrib.monads/maybe-t。
你想写
(def sequence-maybe-m (maybe-t sequence-m))
其中maybe-t
将“maybe”添加到序列monad中。使用它将使
(domonad sequence-maybe-m [a [1 2 3] b [1 nil 3]] (+ a b))
产量
(2 nil 4 3 nil 5 4 nil 6)
这是此类monad的有效输出。如果您需要取消其中包含nil
的结果,只需在monad的输出上使用some nil?
进行检查。
在您的示例中按照要求将nil
绑定到b
(domonad sequence-maybe-m [a [1 2 3] b nil] (+ a b))
也没有意义,因为nil
不是序列。在转换后的monad中,返回值将是空列表()
。将[nil]
绑定到b
更合适,然后你会获得(nil nil nil)
。
有助于记住monad用于组成相同签名的函数,并且它们本身可以是这种组合的一部分,因此它们必须产生monadic值(在本例中为序列)本身,并且在它们的体内任何绑定也必须具有一元价值。