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 一个函数的函数
为了将它们提升到上面的假设实现中。但在我看来有一个微妙的
权力的差异。有什么不同吗? (假设这个问题甚至是有道理的)
您重新发现了 Applicative
的 monoidal 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".
是的,这同样强大。请注意 pure
和 tuple1
是相同的。此外,所有高于 tuple2
的内容都从 tuple2
和 fmap
:
中恢复
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
应用程序通常作为提升多参数函数的一种方式呈现 进入仿函数并将仿函数值应用于它。但我想知道是否有一些 微妙的额外力量源于它可以通过提升来做到这一点 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 一个函数的函数 为了将它们提升到上面的假设实现中。但在我看来有一个微妙的 权力的差异。有什么不同吗? (假设这个问题甚至是有道理的)
您重新发现了 Applicative
的 monoidal 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".
是的,这同样强大。请注意 pure
和 tuple1
是相同的。此外,所有高于 tuple2
的内容都从 tuple2
和 fmap
:
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