我知道点(.)运算符被定义为接受三个参数(两个函数和一个类型为“a”的值),并通过将参数应用于右侧函数的应用程序工作,左侧函数应用于左侧应用程序的输出,如下所示:
-- Associativity: infixr 9
(.) :: (b -> c) -> (a -> b) -> a -> c
(f . g) x = f(g x)
-- Or in another format
f . g = \x -> f(g x)
字符串
现在,这就是在函数复合中使用点运算符的多个应用程序的困惑所在,考虑一下:
使用中缀操作符(如(+)),它接受“”类中类型的两个参数。
(+) :: Num a => a -> a -> a
-- An application would look like this:
> 4 + 3
7
-- With more applications composed with (+)
> 4 + 3 + 2
9
-- Which is fine, since the last application
-- still takes two arguments of the legitimate types,
-- which is a value of type within "Num" class, as follows
> (4 + 3) + 2
-- 7 + 2
9
型
但是使用点运算符,如下所示。最后一个使用点运算符的函数组合应该采用应用程序的输出“reverse . take 3 $ map(*2)[1..]",这是前面函数组合的“[6,4,2]”。
如果这就是我所说的,点运算符接受一个值而不是一个函数和右边的一个值,它应该如何工作?
> replicate 4 . reverse . take 3 $ map (*2) [1..]
[[6,4,2],[6,4,2],[6,4,2],[6,4,2]]
型
中间的舞步不应该是跟步吗?
-- And it's not going to work, since the dot operator
-- is defined to take three arguments of two functions
-- "(b -> c)" and "(a -> b)"
-- and the value of type "a"
replicate 4 . [6,4,2]
型
因为点运算符的应用程序接受三个参数,然后返回类型为“a”的值的结果。
所以左边的“reverse . take 3 $ map(*2)[1..]”部分应该被计算为“[6,4,2]”
为什么不是呢?
2条答案
按热度按时间kxeu7u2r1#
你会被currification弄糊涂(后面会有更多的介绍),你可以把
(.)
看作是接受两个参数(就像(+)
一样)。字符串
现在,因为
(.)
是正确的,所以下面的两行代码是等效的型
为了使这更明确,让我重写上面的代码
型
现在,我们在这里应用的技术被称为currying。可以总结为“一个接受两个参数的函数可以重写为一个接受一个参数的函数,并返回另一个接受一个参数的函数。”
一些python代码,以便于理解
型
现在,所有的haskell函数都是curried的,这实际上在函数式语言上很有意义,因为它简化了很多组合,并使语言在大多数情况下更符合人体工程学(当然,这是一个观点,其他人可能会有不同的看法)
咖喱在开始的时候可能会让人头疼,但最终它会变得很自然。克服它的最好方法是做大量的练习,并尝试使用大量的局部应用
v2g6jxz62#
简而言之,在多功能组合物的应用中,(t.z.f. g)”,函数composition的每个单独的composition将首先从右到左,通过点运算符的“infixr 9”的优先级进行评估,然后应用于参数“x”,因为组合和给定的参数由美元运算符分隔,美元运算符定义为优先级为“infixr 0”。
字符串
现在,由于currying,点运算符被定义为接受两个函数和一个值的三个参数,即“(b -> c)",“(a -> b)”和“a”,如果点运算符只接受这两个函数,那么它将返回一个函数“(a -> c)”作为下一个点运算符的右操作数,依此类推。
型
在一个真实的案例中:
型
它像预期的那样工作:)
感谢@lsmor详细和鼓舞人心的回答。这篇文章是我的理解方式,不是关于哪个更好。非常感谢!