Applicative 接口提供的功能是否超出了将多参数函数(以柯里化形式)提升为 Functor 的能力?

Does the Applicative interface provide power beyond the ability to lift multi-argument functions (in curried form) into a Functor?

应用程序通常作为提升多参数函数的一种方式呈现 进入仿函数并将仿函数值应用于它。但我想知道是否有一些 微妙的额外力量源于它可以通过提升来做到这一点 return 一个函数并应用函数参数的函数 一次。

想象一下,我们定义一个基于提升函数的接口,其参数是一个参数元组:

# from Functor
fmap :: (a -> b) -> Fa -> Fb
# from Applicative
pure :: a -> Fa

# combine multiple functor values into a functor of a tuple
tuple1 :: Fa -> F(a)
tuple2 :: Fa -> Fb -> F(a,b)
tuple3 :: Fa -> Fb -> Fc -> F(a,b,c)
(etc ...)

# lift multi-argument functions (that take a tuple as input)
ap_tuple1 :: ((a) -> b) -> F(a) -> Fb
ap_tuple2 :: ((a,b) -> c) -> F(a,b) -> Fc
ap_tuple3 :: ((a,b,c) -> d) -> F(a,b,c) -> Fd
(etc ..)

假设我们为可能遇到的每个大小的元组定义了相应的元组函数。 这个接口是否和 Applicative 接口一样强大,因为它允许 lifting/applying-to 多参数​​函数但不允许 lifting/applying-to 函数 那return一个函数?显然,可以咖喱以元组作为参数的函数 所以它们可以在一个应用程序中被提升,并且可以取消 return 一个函数的函数 为了将它们提升到上面的假设实现中。但在我看来有一个微妙的 权力的差异。有什么不同吗? (假设这个问题甚至是有道理的)

您重新发现了 Applicativemonoidal presentation。它看起来像这样:

class Functor f => Monoidal f where
    (>*<) :: f a -> f b -> f (a, b)
    unit :: f ()

通过以下方式与 Applicative 同构:

(>*<) = liftA2 (,)
unit = pure ()

pure x = x <$ unit
f <*> x = fmap (uncurry ($)) (f >*< x)

顺便说一下,你的 ap_tuple 函数都只是 fmap。具有多个值的 "hard" 部分将它们组合在一起。将它们拆分成碎片是 "easy".

是的,这同样强大。请注意 puretuple1 是相同的。此外,所有高于 tuple2 的内容都从 tuple2fmap:

中恢复
tuple3 x y z = repair <$> tuple2 (tuple2 x y) z
    where repair ((a, b), c) = (a, b, c)
tuple4 w x y z = repair <$> tuple2 (tuple2 x y) (tuple2 x y)
    where repair ((a, b), (c, d)) = (a, b, c, d)
-- etc.

此外,所有 ap_tuple 都是 fmap:

ap_tuple1 = fmap
ap_tuple2 = fmap
ap_tuple3 = fmap
-- ...

重命名 prod = tuple2,您的问题归结为

Is

class Functor f => Applicative f where
    pure :: a -> f a
    prod :: f a -> f b -> f (a, b)

equivalent to

class Functor f => Applicative f where
    pure :: a -> f a
    liftA2 :: (a -> b -> c) -> f a -> f b -> f c

?

您可能已经看到答案是肯定的。 prod 只是 liftA2

的特化
prod = liftA2 (,)

但是 (,) 是 "natural",因为它没有 "delete" 任何东西,因此您可以通过解构数据来恢复 liftA2

liftA2 f x y = f' <$> prod x y
    where f' (a, b) = f a b