【发布时间】:2018-12-13 13:51:02
【问题描述】:
一些 Haskell 源代码(参见 ref):
-- | Sequential application.
--
-- A few functors support an implementation of '<*>' that is more
-- efficient than the default one.
(<*>) :: f (a -> b) -> f a -> f b
(<*>) = liftA2 id
-- | Lift a binary function to actions.
--
-- Some functors support an implementation of 'liftA2' that is more
-- efficient than the default one. In particular, if 'fmap' is an
-- expensive operation, it is likely better to use 'liftA2' than to
-- 'fmap' over the structure and then use '<*>'.
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
liftA2 f x = (<*>) (fmap f x)
三件事让我很困惑:
1) (<*>) 是根据liftA2 定义的,其中liftA2 是根据(<*>) 定义的。它是如何工作的?我没有看到明显的“递归中断”案例......
2) id 是一个 a -> a 函数。为什么它作为(a -> b -> c) 函数传递给liftA2?
3) fmap id x 总是等于x,因为函子必须保持适当的身份。因此(<*>) (fmap id x) = (<*>) (x) where x = f a - 一个a 类型的函子本身(顺便说一句,a 函子的典型化如何可以从纯范畴论的角度来解释view? functor 只是类别之间的映射,它没有进一步的“典型化”......似乎更好的说法是 -“a 类型的容器,为每个 asummed 类别的实例定义了一个 (endo)functor @ 987654340@ 的定义明确的 Haskell 类型)。所以(<*>) (f a) 而根据定义(<*>) 期望f(a' -> b'):因此,使其工作的唯一方法是故意将a 绑定为(a' -> b')。但是当我在gchi 中运行:t \x -> (<*>) (fmap id x),它吐出一些令人兴奋的东西:f (a -> b) -> f a -> f b - 我无法解释。
有人可以逐步解释它是如何工作的以及为什么它甚至可以编译吗? 附言如果需要,欢迎使用范畴理论术语。
【问题讨论】:
标签: haskell applicative