为什么ap在Applicative中可用?

我正在尝试为 Snap 实现 MonadUnliftIO 并分析 Snap 类。我发现 ap 用于实现 Applicative,而 ap 需要 Monad,Monad 需要 Applicative。它看起来像一个循环。

我认为直到现在不可能写出这样的东西。这种把戏的极限是什么?


class Functor f => Applicative f where
  pure :: a -> f a
  (<*>) :: f (a -> b) -> f a -> f b

class Applicative m => Monad m where
  return :: a -> m a
 
instance Applicative Snap where
  pure x = ...
  (<*>) = ap

ap :: Monad m => m (a -> b) -> m a -> m b

回答

这只有效,因为Snap 一个Monad实例(并且它实际上在当时的范围内)。

实际上,编译器在两个单独的过程中处理声明:首先它解析所有实例头

instance Applicative Snap
instance Monad Snap

...甚至没有查看实际的方法实现。效果很好:Monad只要它看到Applicative实例就很高兴。

那么它已经知道那Snap是一个 monad。然后它继续对(<*>)实现进行类型检查,注意到它需要Monad实例,并且......是的,它在那里,所以也很好。

我们拥有的实际原因ap :: Monad m => ...主要是历史原因:Haskell98Monad类没有Applicative或什Functor至没有超类,因此可能会编写Monad m => ...无法使用fmapor 的代码<*>。因此引入了liftMap函数作为替代。

然后,当建立了更好的当前类层次结构时,许多实例只是通过引用已经存在的Monad实例来定义的,这对于一切来说毕竟已经足够了。

IMO 通常编写实例之前直接实现<*>并且绝对是一个好主意,而不是相反。fmap Monad


以上是为什么ap在Applicative中可用?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>