首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么MFunctor的“提升机”没有“Monad n”约束?

为什么MFunctor的“提升机”没有“Monad n”约束?
EN

Stack Overflow用户
提问于 2014-01-27 21:12:03
回答 2查看 291关注 0票数 8

我有个共线变压器

代码语言:javascript
运行
复制
data Step y m a = Done a | Yield y (CoT y m a)

data CoT y m a = CoT (m (Step y m a))

使用Monad实例

代码语言:javascript
运行
复制
unCoT :: CoT y m a -> m (Step y m a)
unCoT (CoT m) = m

instance Monad m => Monad (CoT y m) where
    return  = CoT . return . Done
    CoT x >>= f = CoT $ do
      x' <- x
      case x' of
        Done a -> unCoT (f a)
        Yield y x' -> return (Yield y (x' >>= f))

如果我定义一个具有Monad mMonad n约束的Monad n类,我可以定义hoist

代码语言:javascript
运行
复制
class MFunctor t where
  hoist :: (Monad n, Monad m) => (forall a. m a -> n a) -> t m b -> t n b

instance MFunctor (CoT y) where
  hoist f (CoT m) = CoT $ do
    step <- f m
    return (case step of Done x     -> Done x
                         Yield y m' -> Yield y (hoist f m'))

但是mmorphhoist只有一个Monad m约束,我可以在没有它的情况下定义自己的hoist,还是缺乏MFunctor的通用性?

编辑:我想这是可能的!但我的问题仍然存在:我们确定这里不缺乏一般性吗?

代码语言:javascript
运行
复制
instance MFunctor (CoT y) where
  hoist f (CoT m) = CoT $ f $ do
    step <- m
    return (case step of Done x     -> Done x
                         Yield y m' -> Yield y (hoist f m'))
EN

回答 2

Stack Overflow用户

发布于 2014-01-28 05:31:10

mmorph是在pipes-3.*系列(以前是 module)的上下文中开发的,其功能如下:

代码语言:javascript
运行
复制
raise
    :: (Monad m, MFunctor t1, MonadTrans t2)
    => t1 m r -> t1 (t2 m) r
raise = hoist lift

如果将Monad n约束添加到hoist,则必须向raise添加Monad (t2 m)约束。我通常会尽量减少库中的约束,并且找不到任何需要Monad n约束的Monad n实例,所以我删除了它。

附带注意:CoT y m a和来自pipesProducer y m a是一样的,后者已经有了MFunctor实例。

票数 8
EN

Stack Overflow用户

发布于 2017-01-23 22:28:40

您可以使用可以将t定义为MFunctor的任何类型的MFunctor。但是,只有在t n a上有一个Monad实例时,才能使用生成的n。我们通过推迟自然变换的应用来做到这一点。或者用一种奇特的方式来表达这一点,那就是运用coyoneda引理。

代码语言:javascript
运行
复制
{-# LANGUAGE RankNTypes, GADTs #-}

import Control.Monad.Morph

-- Slightly weaker than MFunctor due to the monad constraint on n.
class MFunctor' t where
  hoist' :: (Monad m, Monad n) => (forall b. m b -> n b) -> t m a -> t n a

data MCoyoneda t n a where
  MCoyoneda :: Monad m => (forall b. m b -> n b) -> t m a -> MCoyoneda t n a

liftMCoyoneda :: Monad m => t m a -> MCoyoneda t m a
liftMCoyoneda = MCoyoneda id

lowerMCoyoneda' :: (MFunctor' t, Monad n) => MCoyoneda t n a -> t n a
lowerMCoyoneda' (MCoyoneda f tma) = hoist' f tma

-- The result is actually slightly stronger than 'MFunctor', as we do not need
-- a monad for 'm' either.
hoistMCoyoneda :: (forall b. m b -> n b) -> MCoyoneda t m a -> MCoyoneda t n a
hoistMCoyoneda f (MCoyoneda trans tma) = MCoyoneda (f . trans) tma

instance MFunctor (MCoyoneda t) where
  hoist = hoistMCoyoneda

所以我不认为我们失去了通用性,因为如果您不能为MFunctor实现一个实例,那么lowerMCoyoneda'上的Monad约束就不会丢失任何东西。

我发现这是在RVarT上运行的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21391770

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档