[英]Can a monad be a comonad?
I know what a monad is. 我知道monad是什么。 I think I have correctly wrapped my mind around what a comonad is.
我想我已经正确地把我的想法包围在一个comonad是什么。 (Or rather, what one is seems simple enough; the tricky part is comprehending what's useful about this...)
(或者说,什么是一个似乎很简单;棘手的部分是理解什么是关于这个有用的 ...)
My question is: Can something be a monad and a comonad? 我的问题是:有什么东西可以成为monad 和 comonad吗?
I foresee two possible answers: 我预见到两个可能的答案:
So, which is it? 那么,这是什么?
The Cofree Comonad yields some data structures that are useful as Monads and Comonads both: Cofree Comonad产生一些数据结构,可用作Monads和Comonads:
data Cofree f a = a :< f (Cofree f a)
Every Cofree Comonad over an Alternative functor yields a Monad -- see the instance here: 每个Cofree Comonad上的另一个仿函数产生一个Monad - 请参见此处的实例:
http://hackage.haskell.org/packages/archive/free/3.4.1/doc/html/Control-Comonad-Cofree.html http://hackage.haskell.org/packages/archive/free/3.4.1/doc/html/Control-Comonad-Cofree.html
instance Alternative f => Monad (Cofree f) where
return x = x :< empty
(a :< m) >>= k = case k a of
b :< n -> b :< (n <|> fmap (>>= k) m)
This gives us, eg nonempty lists as Monads and Comonads both (along with nonempty f-branching trees, etc). 这给了我们,例如Monad和Comonads的非空列表(以及非空的f分支树等)。
Identity
is not an alternative, but Cofree Identity
yields an infinite stream, and we can in fact give a different monad instance to that stream: Identity
不是替代方案,但Cofree Identity
产生无限的流,我们实际上可以为该流提供不同的 monad实例:
http://hackage.haskell.org/packages/archive/streams/3.1/doc/html/Data-Stream-Infinite.html http://hackage.haskell.org/packages/archive/streams/3.1/doc/html/Data-Stream-Infinite.html
data Stream a = a :> Stream a
instance Comonad Stream where
duplicate = tails
extend f w = f w :> extend f (tail w)
extract = head
instance Monad Stream where
return = repeat
m >>= f = unfold (\(bs :> bss) -> (head bs, tail <$> bss)) (fmap f m)
(note the functions above are not on lists but instead defined in the streams
package). (注意上面的函数不在列表中,而是在
streams
包中定义)。
Similarly the reader arrow is not an alternative, but Cofree ((->) r)
yields a Moore machine, and Moore machines also are monads and comonads both: 类似地,读者箭头不是替代品,但
Cofree ((->) r)
产生一个Moore机器,而Moore机器也是monad和comonads:
http://hackage.haskell.org/packages/archive/machines/0.2.3.1/doc/html/Data-Machine-Moore.html http://hackage.haskell.org/packages/archive/machines/0.2.3.1/doc/html/Data-Machine-Moore.html
data Moore a b = Moore b (a -> Moore a b)
instance Monad (Moore a) where
return a = r where r = Moore a (const r)
Moore a k >>= f = case f a of
Moore b _ -> Moore b (k >=> f)
_ >> m = m
instance Comonad (Moore a) where
extract (Moore b _) = b
extend f w@(Moore _ g) = Moore (f w) (extend f . g)
So what's the intuition behind all these examples? 那么所有这些例子背后的直觉是什么? Well we get the comonadic operations for free.
好吧,我们免费获得comonadic操作。 The monadic operations we get are all forms of diagonalization.
我们得到的monadic操作都是对角化的形式。 With alternative we can
<|>
things together to "smush" the structure, and magic up "empty" things when we run out of structure to smush. 有了替代方案,我们可以
<|>
一起“刷掉”结构,并且当我们用完结构来抹去时,魔术上升“空”。 This lets us work on finite cases. 这让我们可以处理有限的案例。 Lacking alternative we need to have an indefinite amount of structure, so that no matter how many "join" operations (which we can think of as splicing or substitution) that we make, there's always more room to place the spliced elements (like at the Hilbert Hotel: http://www.encyclopediaofmath.org/index.php/Hilbert_infinite_hotel ).
缺乏替代方案我们需要有一个无限量的结构,这样无论我们制造了多少“连接”操作(我们可以认为是拼接或替换),拼接元素总是有更多的空间(比如希尔伯特酒店: http : //www.encyclopediaofmath.org/index.php/Hilbert_infinite_hotel )。
Relatedly, every Comonad gives rise to a related Monad (although I consider this more a curiousity): 相关地, 每个 Comonad都会产生一个相关的Monad(尽管我认为这更像是一个好奇心):
http://hackage.haskell.org/packages/archive/kan-extensions/3.1.1/doc/html/Control-Monad-Co.html http://hackage.haskell.org/packages/archive/kan-extensions/3.1.1/doc/html/Control-Monad-Co.html
http://comonad.com/reader/2011/monads-from-comonads/ http://comonad.com/reader/2011/monads-from-comonads/
Yes. 是。 Turning some comments into an answer:
将一些评论转化为答案:
newtype Identity a = Identity {runIdenity :: a} deriving Functor
instance Monad Identity where
return = Identity
join = runIdentity
instance CoMonad Identity where
coreturn = runIdentity
cojoin = Identity
Reader and Writer are exact duals, as shown by 读者和作者是精确的对偶,如图所示
class CoMonoid m where
comempty :: (m,a) -> a
comappend :: m -> (m,m)
--every haskell type is a CoMonoid
--that is because CCCs are boring!
instance Monoid a => Monad ((,) a) where
return x = (mempty,x)
join (a,(b,x)) = (a <> b, x)
instance CoMonoid a => CoMonad ((,) a) where
coreturn = comempty
cojoin = associate . first comappend
instance CoMonoid a => Monad ((->) a) where
return = flip (curry comempty)
join f = uncurry f . comappend
instance Monoid a => CoMonad ((->) a) where
coreturn f = f mempty
cojoin f a b = f (a <> b)
There are many interesting structures that are both a Monad
and a Comonad
. 有许多有趣的结构既是
Monad
又是Comonad
。
The Identity
functor has been pointed out here by several other people, but there are non-trivial examples. 其他几个人已经在这里指出了
Identity
仿函数,但是有一些非常重要的例子。
The Writer
Monad
plays a Reader
-like role as a Comonad
. Writer
Monad
扮演类似Reader
的角色,作为Comonad
。
instance Monoid e => Monad ((,) e)
instance Comonad ((,) e)
The Reader
Monad
plays a Writer
-like role as a Comonad
. Reader
Monad
扮演着像Comonad
一样的Writer
角色。
instance Monad ((->) e)
instance Monoid e => Comonad ((->)e)
Non-empty lists also form both a monad and a comonad and are in fact a special case of a larger construction involving cofree comonads. 非空列表也形成monad和comonad,实际上是涉及cofree comonad的更大结构的特例。 The
Identity
case can also be seen as a special case of this. Identity
案例也可以视为一种特殊情况。
There are also various Yoneda
and Codensity
-like constructions based on Kan extensions, that work to transform monads and comonads, although they favor one or the other in terms of operational efficiency. 还有各种基于Kan扩展的
Yoneda
和Codensity
的构造,它们可以转换monad和comonads,尽管它们在运行效率方面偏向于其中一个或另一个。
I also have an adapter that converts an arbitrary comonad into a monad transformer. 我还有一个适配器,可以将任意comonad转换为monad转换器。 Sadly the opposite conversion isn't possible in Haskell.
可悲的是,在Haskell中不可能进行相反的转换。
In linear algebra there is a notion of a bialgebra . 在线性代数中有一个双代数的概念。 Ideally if we have something that forms both a
Monad
and a Comonad
and we want to use those operations together without reasoning on a case-by-case basis, one would like to have that return
and join
are Comonad coalgebras and by extension that extract
and duplicate
are Monad
algebras. 理想情况下,如果我们有一些形成
Monad
和Comonad
东西,并且我们希望在没有任何理由的情况下一起使用这些操作,那么人们希望return
并join
Comonad余代数,并通过扩展来extract
和duplicate
是Monad
代数。 If those conditions hold then you can actually reason about code that has both Monad f
and Comonad f
constraints and mixes the combinators from each without case-by-case reasoning. 如果这些条件成立,那么你实际上可以
Comonad f
出具有Monad f
和Comonad f
约束的代码,并且混合各自的组合子而没有逐案推理。
It depends on what you consider a "monad" to be. 这取决于你认为是什么“monad”。 If you ask "is it possible for a type to be an instance of both
Monad
and Comonad
at once?" 如果你问“一个类型是否可以同时成为
Monad
和Comonad
的实例?” then, yes. 好的。 Here's a trivial example.
这是一个简单的例子。
newtype Id a = Id a
instance Monad Identity where
return = Id
(Id a) >>= f = f a
instance Comonad Identity where
extract (Id a) = a
extend f ida = Id (f ida)
If you mean it mathematically, then a monad is a triple (X, return, bind)
where X
is a type and return
and bind
follow the types and laws you expect. 如果你的数学意思是,那么monad是一个三元组
(X, return, bind)
,其中X
是一个类型, return
和bind
遵循你期望的类型和规则。 Similarly, a comonad is (X, extend, extract)
. 类似地,comonad是
(X, extend, extract)
。 I've just demonstrated that the X
s might be the same, but since the types of extend
and return
or extract
and bind
are different it's not possible for them to be the same functions. 我刚刚证明了
X
可能是相同的,但由于extend
和return
或extract
和bind
类型不同,因此它们不可能是相同的函数。 So a mathematical monad can never be a comonad. 所以数学monad永远不会是一个comonad。
Expanding on Hammer's suggestion, it seems simple enough to write a function [x] -> [[x]]
. 扩展Hammer的建议,编写函数
[x] -> [[x]]
似乎很简单。 For example, 例如,
map (\ x -> [x])
would work just fine. 会工作得很好。 So it looks like lists could form a comonad.
所以看起来列表可能形成一个comonad。 Ah, but wait.
啊,等等。 That handles
cojoin
, but what about coreturn :: [x] -> x
? 处理
cojoin
,但coreturn :: [x] -> x
怎么样? This , presumably, is why only non-empty lists form a comonad. 据推测, 这就是为什么只有非空列表形成一个comonad。
This gives us a cobind function with the type ([x] -> x) -> [x] -> [x]
. 这给了我们一个cobind函数类型
([x] -> x) -> [x] -> [x]
。 Interestingly, Hoogle knows of no such function. 有趣的是,Hoogle知道没有这样的功能。 And yet we already have
concatMap :: (x -> [x]) -> [x] -> [x]
. 然而我们已经有了
concatMap :: (x -> [x]) -> [x] -> [x]
。 I'm not seeing an immediate use for the cobind function, but I can imagine one existing. 我没有看到cobind函数立即使用,但我可以想象一个存在。
I'm still trying to wrap my mind around comonad and what it might be useful for. 我仍然试图围绕comonad以及它可能有用的内容。 The answers so far have given me something to think about...
到目前为止的答案让我有所思考......
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.