Applicative为什么要继承Functor?

Why should Applicative inherit from Functor?

确实如此:

λ :i Applicative 
class Functor f => Applicative (f :: * -> *) where

同时:

fmap f x = pure f <*> x

— 根据 Applicative 的定律,我们可以从 pure & <*>.

定义 fmap

我不明白为什么每次我想要 Applicative 时我都要繁琐地定义 fmap 如果真的 fmap 可以根据 [=14] 自动设置=] 和 <*>.

我猜想如果 pure<*> 以某种方式依赖于 fmap 的定义,但我不明白为什么他们必须这样做。

虽然 fmap 可以从 pure<*> 派生,但它通常不是最有效的方法。比较:

fmap :: (a -> b) -> Maybe a -> Maybe b
fmap f Nothing = Nothing
fmap f (Just x) = Just (f x)

使用应用工具完成的工作:

fmap :: (a -> b) -> Maybe a -> Maybe b
-- inlining pure and <*> in: fmap f x = pure f <*> x
fmap f x = case (Just f) of
  Nothing -> Nothing
  Just f' -> case x of
    Nothing -> Nothing
    Just x' -> Just (f' x')

毫无意义地将一些东西包装在构造函数中只是为了对其进行模式匹配。

所以,很明显,能够独立于应用函数定义 fmap 是很有用的。 可以 通过使用所有三个函数创建一个类型类来完成,使用您可以覆盖的 fmap 的默认实现。但是,有些类型可以生成好的 Functor 实例,但不能生成好的 Applicative 实例,因此您可能只需要实现一个。因此,两个类型类。

并且由于没有类型具有 Applicative 实例但没有 Functor 实例,如果您愿意,您应该能够将 Applicative 视为 Functor;因此两者之间的扩展关系。

但是,如果您厌倦了实现 Functor,您可以(在大多数情况下)要求 GHC 为您派生 Functor 的唯一可能实现,

{-# LANGUAGE DeriveFunctor #-}
data Boring a = Boring a deriving Functor

虽然有一些建议可以使它变得更容易 https://ghc.haskell.org/trac/ghc/wiki/IntrinsicSuperclasses,但 "default instances" 问题本身非常困难。

一个挑战是如何处理公共超类:

fmap f x = pure f <*> x                            -- using Applicative
fmap f x = runIdentity (traverse (Identity . f) x) -- using Traversable
fmap f x = x >>= (return . f)               -- using Monad

选哪个?

所以我们现在能做的最好的事情就是提供 fmapDefault(就像 Data.Traversable)一样;或使用 pure f <*> x;或 fmapRep 来自 Data.Functor.Rep(如果适用)。