范畴论中的单子词由三元组 T,单位,平坦⟩定义。
class Monad t where
map :: (a -> b) -> (t a -> t b) -- functorial action
unit :: a -> t a
flat :: t (t a) -> t a
class KleisliTriple t where
unit :: a -> t a
flatMap :: t a -> (a -> t b) -> t b
KleisliTriple通过由flatMap
和bind
组成的map
(或Haskell中的flat
)运算符来对结构进行平整。
但是,我一直认为,理解和实现函数式编程中的Monad概念以使对象{例如flatUnit
和unit
flat
。
在这种情况下,flatUnit(flatUnit(x)) = flatUnit(x)
。我实际上是在JavaScript中以这种方式实现的,并且使用flatUnit
和map
(只是一个传统的函子运算符),似乎可以得到Monad的所有好处。
所以,这是我的问题。
我一直在寻找有关函数编程中flatUnit
形式化的文档,但从未找到。我了解有一个历史背景,Eugenio Moggi首先发现了函数式编程中monad的相关性,并且在他的论文中碰巧是KleisliTriple应用程序,但是由于Monad不限于Kleisli类别并且考虑了flatUnit
的简单性,对我来说很奇怪。
那是为什么?我想念什么?
编辑:代码已删除。
答案 0 :(得分:10)
在这个答案中,我不会停留在flatUnit
上。正如其他人指出的那样,join . return = id
适用于任何monad(这是monad法则之一),因此就其本身而言,没有太多要讨论的内容。相反,我将讨论此处讨论中提出的一些周围主题。
引用评论:
换句话说,具有扁平结构的函子是单子。
我认为,这是问题的核心。 monad不必是具有平坦结构的函子,而可以是其值可以按照某些定律(“类别中的类齐半体”)被 tened (带有join
)的函子。俗话说)。平整化不需要是无损操作(即join
是同构)。
join
是同构的Monad,在范畴论中被称为idempotent monads 1 。但是,要使Haskell Monad
成为幂等,单价值必须没有额外的结构。这意味着程序员最关注的大多数monad并不是幂等的(实际上,我很难想到不是Monad
或类似身份的幂等的Haskell Identity
)。评论中已经提出的一个示例是列表:
join [[1,2],[3,4,5]] = [1,2,3,4,5] -- Grouping information discarded
函数/阅读器monad给出了一个更加生动的插图:
join (+) = \x -> x + x
This recent question提供了涉及Maybe
的有趣插图。那里的OP具有签名功能...
appFunc :: Integer -> Integer -> Bool -> Maybe (Integer,Integer)
...并像这样使用它...
appFunc <$> u <*> v <*> w
...从而获得Maybe (Maybe (Integer, Integer))
的结果。 Maybe
的两层分别对应两种不同的失败方式:如果u
,v
或w
为Nothing
,我们得到Nothing
;如果失败,则失败。如果其中三个是Just
值,但appFunc
的结果是Nothing
,则得到Just Nothing
;最后,如果一切成功,我们将在Just
中获得一个Just
值。现在,可能像我们这个问题的作者一样,我们并不在意Maybe
的哪一层导致了失败。在这种情况下,我们可以通过在结果上使用join
或将其重写为u >>= \x -> v >>= \y -> w >>= \b -> appFunc x y b
来丢弃该信息。无论如何,这些信息都可以供我们使用或丢弃。
注1:在King和Wadler(Wadler's papers about monads之一)的 Combining Monads 中,作者引入了一个不同的,且几乎无关的含义,即“幂等单子”。从他们的意义上讲,一个幂等单子是f <$> u <*> u = (\x -> f x x) <$> u
的一个例子(适用的表示法)是Maybe
。