gpt4 book ai didi

haskell - `(<*>)` 应用仿函数的定义?

转载 作者:行者123 更新时间:2023-12-04 13:10:32 25 4
gpt4 key购买 nike

一些 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 函数。为什么它作为 liftA2 函数传入 (a -> b -> c)

3) fmap id x 总是等于 x ,因为仿函数必须保持适当的身份。因此 (<*>) (fmap id x) = (<*>) (x) 其中 x = f a - 一个 a 类型的仿函数本身(顺便说一句,如何从纯范畴论的角度解释仿函数的 a 典型化?仿函数只是类别之间的映射,它有没有进一步的“典型化”......似乎最好说 - “类型为 a 的容器,为定义明确的 Haskell 类型的总分类 Hask 的每个实例定义(endo)仿函数)。所以 (<*>) (f a) 而根据定义为 (<*>)期望 f(a' -> b') :因此,使其工作的唯一方法是故意将 a 绑定(bind)为 (a' -> b') 。但是,当我在 :t \x -> (<*>) (fmap id x) 中运行 gchi 时,它会吐出一些令人兴奋的东西: f (a -> b) -> f a -> f b - 我无法解释。

有人可以逐步解释它是如何工作的以及为什么它甚至可以编译吗?
附言如果需要,欢迎使用范畴理论术语。

最佳答案

对于问题 1,您遗漏了一个非常重要的上下文。

class Functor f => Applicative f where
{-# MINIMAL pure, ((<*>) | liftA2) #-}

您引用的那些定义属于一个类。这意味着实例可以覆盖它们。此外,MINIMAL pragma 说,为了工作,至少其中一个必须在实例中被覆盖。因此,只要在特定实例中重写递归,就会发生递归中断。这就像 Eq类定义 (==)(/=)彼此之间,因此您只需要在手写实例中提供一个定义。

对于问题二, a -> b -> ca -> (b -> c) 的简写.所以它与(让我们重命名变量以避免冲突) d -> d(b -> c) -> (b ->c) . (切线,这也是 ($) 的类型。)

对于三个 - 你是绝对正确的。继续简化!
\x -> (<*>) (fmap id x)
\x -> (<*>) x
(<*>)

所以 ghci 给你的类型是 (<*>) 并不奇怪。回来,应该吗?

关于haskell - `(<*>)` 应用仿函数的定义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53763376/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com