Haskell 功能组合(.)是如何从内部工作的?
我在学习哈斯克尔。目前,我正在学习函数合成。我了解(至少在基本层面上)如何使用函数Haskell 功能组合(.)是如何从内部工作的?,haskell,lambda,syntax,function-composition,Haskell,Lambda,Syntax,Function Composition,我在学习哈斯克尔。目前,我正在学习函数合成。我了解(至少在基本层面上)如何使用函数(.),但有两件事我不了解 因此,函数如下所示: (.) :: (b -> c) -> (a -> b) -> a -> c f . g = \x -> f (g x) 首先,类型声明(b->c)->(a->b)本质上意味着函数f从函数g(取值a)的结果值(b)中获取一个参数,并返回c类型的值。我不明白下面的部分->a->c,为什么那里应该有->a?为什么(b->c)->(a-
(.)
,但有两件事我不了解
因此,函数如下所示:
(.) :: (b -> c) -> (a -> b) -> a -> c
f . g = \x -> f (g x)
首先,类型声明(b->c)->(a->b)
本质上意味着函数f
从函数g
(取值a
)的结果值(b
)中获取一个参数,并返回c
类型的值。我不明白下面的部分->a->c
,为什么那里应该有->a
?为什么(b->c)->(a->b)->c
错了?在我看来(这显然是错误的),函数g
已经将a
作为参数
第二,函数体f。g=\x->f(gx)
。\x->
在这里做什么?Lambda非常直截了当。例如过滤器(\(a,b)->a+b>4)[(1,2)、(3,4)]
,但是一个简单的\x->
会让我陷入困境。我可能会这样写身体f。(gx)=f(gx)
(这显然又错了)。(b->c)->(a->b)->c
将是一个函数,它包含两个函数f::b->c
和g::a->b
,并以某种方式调用g
,而不使用a
类型的初始参数
对于第二个问题,考虑如何使用前缀表示法来定义<代码>(?)/COD>。(如果我们为函数使用“常规”名称,可能会更容易看到;我将在每个代码片段后面添加注释):
x
是(.)
的“第三个参数”,或者更准确地说是(.)f g
返回的函数的参数。这相当于通过将函数放在右侧而不是该函数的最终返回值,将(.)f g
直接定义为函数:
(.) f g x = f (g x) -- Implicit function def: compose f g x = f (g x)
(.) f g = \x -> f (g x) -- Explicit function def: compose f g = \x -> f (g x)
也可以使用括号隐式定义函数:
(f . g) x = f (g x)
可能更容易理解为
()::Fun1->Fun2->Fun3
,也就是说,(。
接受一个Fun1
类型的参数(一个函数),然后是另一个Fun2
类型的参数(另一个函数),并返回一个Fun3
类型的值(另一个函数,“组合”函数)。具体来说,Fun1=(b->c)
,Fun2=(a->b)
,以及Fun3=(a->c)
。实际上,你可以在你的类型中的a->c
周围加上括号——它们是隐式的;这里有一对隐含的括号,尽可能向右,所以f。g=\x->f(gx)
实际上是f。g=(\x->f(gx))
,一个lambda(a的表示法)函数。使用显式lambda定义它的原因与GHC编译器中程序优化的细节有关。作为初学者,您当然不必担心这些问题,但编写关键库函数的人确实考虑到了这一点,这是很有帮助的,这样您的代码运行得更快。
(f . g) x = f (g x)