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