2012-09-08 23 views
0

我需要编写一个'序列,也许m'(monad结合序列monad的行为与可能monad)的帮助。写一个序列 - 也许monad使用clojure.algo.monads

该规则应当是:

  • 如果任何输入是零,那么整个表达失败。
  • 否则,就像序列单子会做的那样评估身体。
 
    (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 <...> 
     ]) 

其中< ...>的功能。

回答

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 

的唯一一点确实值得密切关注着这里是在m-bind第二nil-or-has-nil?。第一个是预期的 - 通过一个monadic值,m-bind必须确定它是否为nil -ish,并应立即导致nil。第二个检查计算结果 - 如果失败(产生任何nil),则总体结果必须是nil(而不是由(apply concat [nil nil ...])产生的空列表)。

+0

辉煌。谢谢! – zcaudate

3

domonad的输出必须是单值,在sequence-m的情况下,这意味着它必须是一个序列。要求输出nil打破这一点,你没有monad。

你可能正在寻找的是直接使用monadic变换器添加“maybe”到序列monad,很容易做到,并在这里描述:http://clojuredocs.org/clojure_contrib/1.2.0/clojure.contrib.monads/maybe-t

你会想要写

(def sequence-maybe-m (maybe-t sequence-m)) 

其中maybe-t增加了“可能”的序列单子。使用这将使

(domonad sequence-maybe-m [a [1 2 3] b [1 nil 3]] (+ a b)) 

产量

(2 nil 4 3 nil 5 4 nil 6) 

这是这种类型的单子有效输出。如果您需要取消其中包含nil的结果,只需在单元的输出上使用some nil?来检查它们。

绑定nilb,你在你的例子

(domonad sequence-maybe-m [a [1 2 3] b nil] (+ a b)) 

要求没有任何意义,因为相关nil是不是一个序列。在转换后的monad中,返回值将是空列表()。将[nil]绑定到b会更合适,那么您将获得(nil nil nil)

它有助于记住,单子用于组成相同的签名功能和本身可以是这样的组合物的一部分,因此它们必须产生一元值(在这种情况下,序列)自己和他们的身体的任何结合绝也有一个monadic价值。