如何在Typeclass Show中用"a"定义Monad实例"m a"?

fro*_*h03 6 monads haskell

我想定义一个monad实例,其中容器M为monad,并且包含的​​类型a应该是类的成员Show.应该通过类型系统来确保该约束(其a成员Show).

我尝试过这样的尝试,但M遗憾的是不合适:

data M = forall a. Show a => M a 

instance Monad M where
 return x = M x
Run Code Online (Sandbox Code Playgroud)

所有其他尝试实现这一点,遇到以下问题:由于Monad是一个构造函数类,我没有显式访问a所包含元素的类型,所以我不能限制它.

没有定义新Monad类,有没有人知道这个解决方案?

C. *_*ann 7

好吧,实际上可以使用GADT在某种意义上限制类型构造函数的参数:

data M a where
    M :: (Show a) => a -> M a
Run Code Online (Sandbox Code Playgroud)

不幸的是,这实际上对你没有帮助.在某种程度上,它实际上使事情变得更糟,因为不是Monad没有约束的实例,根本不可能编写实例.

如果你看一下上面的构造函数类型签名,它显然类似于 - 它return说明了为什么你所做的事情从根本上是不可能的.返回的类型是:(Monad m) => a -> m a和始终未绑定的类型变量在最外层隐式普遍量化,因此您可以将其读作"对于所有可能的类型a,以及m作为实例的所有可能类型Monad,给定类型的值,a您可以构造一个类型为m a" 的值"."for all"短语在那里非常直接 - 返回的类型不仅仅是使用类型变量,而是主动声明a必须允许任何类型.

所以,简而言之,没有.没有办法做你想要的,因为标准Monad明确指出相反的.


Dan*_*ner 5

您可能无法完全按照自己的要求行事,但另一种可能性是您的特定单身人士提供明确做出您正在考虑的任何行动的行动Show.也就是说,假设你有:

data M a = {- ... -}
instance Monad M where -- notice: no Show constraint
    {- ... -}
Run Code Online (Sandbox Code Playgroud)

然后你可以另外提供一些动作:

report :: Show a => M a -> M a
Run Code Online (Sandbox Code Playgroud)

我无法想到充分利用这种模式的头脑Show,但我知道一个类似的例子,你可能希望有一个Ord约束.设置是你想制作一个不确定(如[a])的monad ,但没有重复(如Set a).删除重复项需要一些像Eq或的上下文Ord,但我们不能要求每个return/ >>=操作.因此,我们要求用户明确标记应该合并重复项的点:

newtype Setlike a = Setlike { toList :: [a] }
instance Monad Setlike where
    return x = Setlike [x]
    Setlike xs >>= f = [y | x <- xs, let Setlike ys = f x, y <- ys]

collapse :: Ord a => Setlike a -> Setlike a
collapse = Setlike . Data.Set.toList . Data.Set.fromList . toList
Run Code Online (Sandbox Code Playgroud)

这可以这样使用:

valuesOfInterest = collapse $ do
    v1 <- allValues
    v2 <- allValues
    doSomethingInteresting v1 v2
Run Code Online (Sandbox Code Playgroud)

然后,即使某些配对v1v2碰巧产生相同的感兴趣值,该值也只会在结果中出现一次.

您的用例也可能有类似的技巧.