通用嵌套 monad 操作?

Generic nested monad manipulation?

我已经given以下class界面:

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,具有多个参数:

class Misty m => VeryMisty m a where
  ... banana' (Just (Just v)) = banana --? 

我不确定如何在 Misty 中创建一个函数来操作这个嵌套的 monad?

我也不确定我的做法是否正确and/or最简单?

我认为您不必扩展 class,或添加子class。如果您在 banana 的签名中为 a 选择 m a,请考虑 banana 的类型签名是什么样的(类型变量 a 可以代表任何类型,m a):

banana :: Misty m => (m a -> m b) -> m (m a) -> m b

您是否看到这看起来已经开始非常接近 jellybean?您只需要 "get rid" 第一个参数,并使 ba 相同。实现此目的的最简单方法是使用恒等函数 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

所以你在这里看到了在这种情况下进行这种类型检查需要什么。