简体   繁体   English

monad可以成为comonad吗?

[英]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: 我预见到两个可能的答案:

  • Yes, this is common and widely useful. 是的,这是常见且广泛有用的。
  • No, they do such different jobs that there would be no reason to want something to be both. 不,他们做了不同的工作,没有理由想要两者兼而有之。

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扩展的YonedaCodensity的构造,它们可以转换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. 理想情况下,如果我们有一些形成MonadComonad东西,并且我们希望在没有任何理由的情况下一起使用这些操作,那么人们希望returnjoin Comonad余代数,并通过扩展来extractduplicateMonad代数。 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 fComonad 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?" 如果你问“一个类型是否可以同时成为MonadComonad的实例?” 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是一个类型, returnbind遵循你期望的类型和规则。 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可能是相同的,但由于extendreturnextractbind类型不同,因此它们不可能是相同的函数。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM