0

我需要帮助来编写“sequence-maybe-m”(一个结合了序列单子和可能单子的行为的单子)。

规则应该是:

  • 如果任何输入为 nil,则整个表达式失败。
  • 否则,像序列单子一样评估身体。
    (domonad 序列-maybe-m [a [1 2 3] b [1 2 3]] (+ ab))
        ;; => (2 3 4 3 4 5 4 5 6)

    (domonad 序列-maybe-m [a [1 2 3] b nil] (+ ab))
        ;; => 无

    (domonad 序列-maybe-m [a [1 2 3] b (范围 a)] (+ ab))
        ;; => (1 2 3 3 4 5) 与“for”相同

    (domonad 序列-maybe-m [a [1 2 3] b [1 nil 3]] (+ ab))
        ;; => 无

如果它与 clojure.algo.monads 库兼容,那将是一个奖励:

(defmonad sequence-maybe-m
     [m-result <...>
      m-bind   <...>
      m-zero   <...>
      m-plus   <...>
      ])

其中 <...> 是函数。

4

2 回答 2

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. 第一个是预期的 - 传递了一个单子值,m-bind必须确定它是否是nil-ish 并且应该立即导致nil. 第二个检查计算的结果 - 如果它失败(产生任何nil),那么整体结果必须是nil(相对于,例如,产生的空列表(apply concat [nil nil ...]))。

于 2012-09-08T20:37:36.370 回答
3

的输出domonad必须是一元值,在这种情况下sequence-m意味着它必须是一个序列。要求输出nil中断并且您没有单子。

您可能正在寻找的是直接使用单子转换器将“可能”添加到序列单子中,这很容易做到并在此处描述:http: //clojuredocs.org/clojure_contrib/1.2.0/clojure.contrib.monads/maybe -t

你会想写

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

wheremaybe-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?在 monad 的输出上使用来检查它们。

按照您在示例中的要求绑定nilb

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

也没有意义,因为nil它不是一个序列。在转换后的 monad 中,返回值将是空列表()[nil]绑定到会更合适b,然后你会得到(nil nil nil).

它有助于记住 monad 用于组合具有相同签名的函数,并且它们本身可以是这种组合的一部分,因此它们必须自己产生 monadic 值(在这种情况下为序列),并且在它们的主体中,任何绑定也必须与一元值。

于 2012-11-01T21:19:36.247 回答