我一直是given以下的类接口:
class Misty m where
banana :: (a -> m b) -> m a -> m b
unicorn :: a -> m a
现在我需要修改它以启用:
jellybean :: (Misty m) => m (m a) -> m a
我认为这个问题迫使我要添加一个Misty
的子类,其中包含多个参数:
class Misty m => VeryMisty m a where
... banana' (Just (Just v)) = banana --?
我不确定如何在Misty
中创建一个函数来操作这个嵌套的monad?
我也不确定我的方法是否正确和/或最简单?
答案 0 :(得分:5)
我认为你不必扩展类,或者添加子类。如果您要在banana
的签名中为m a
选择a
,请考虑banana
的类型签名是什么(类型变量a
可以代表任何类型,也适用于m a
):
banana :: Misty m => (m a -> m b) -> m (m a) -> m b
你是否看到这已经开始看起来非常接近jellybean
了?您只需要“摆脱”第一个参数,并使b
与a
相同。实现此目标的最简单方法是使用标识函数id
:
jellybean :: (Misty m) => m (m a) -> m a
jellybean x = banana id x
更容易看到第二步的好方法是,一旦发现可以使用jellybean
的第一个参数,因为banana
的第二个参数是使用类型的洞:
jellybean :: (Misty m) => m (m a) -> m a
jellybean x = banana _ x
在将其加载到REPL中时,Haskell将打印出来:
Found hole `_' with type: m a -> m a
所以你在这里看到了你需要做什么才能做出这个类型检查。