(f .) 有什么作用?g 在 Haskell 中是什么意思? [英] What does (f .) . g mean in Haskell?
问题描述
我见过很多函数都是按照 (f .) 模式定义的.g
.例如:
I have seen a lot of functions being defined according to the pattern (f .) . g
. For example:
countWhere = (length .) . filter
duplicate = (concat .) . replicate
concatMap = (concat .) . map
这是什么意思?
推荐答案
点运算符(即 (.)
)是 函数组合 运算符.其定义如下:
The dot operator (i.e. (.)
) is the function composition operator. It is defined as follows:
infixr 9 .
(.) :: (b -> c) -> (a -> b) -> a -> c
f . g = x -> f (g x)
如你所见,它需要一个 b 类型的函数 ->c
和另一个 a -> 类型的函数b
并返回 a -> 类型的函数c
(即将第一个函数应用于第二个函数的结果).
As you can see it takes a function of type b -> c
and another function of type a -> b
and returns a function of type a -> c
(i.e. which applies the first function to the result of the second function).
函数组合运算符非常有用.它允许您将一个函数的输出通过管道传输到另一个函数的输入中.例如你可以写一个 tac Haskell 程序如下:
The function composition operator is very useful. It allows you to pipe the output of one function into the input of another function. For example you could write a tac program in Haskell as follows:
main = interact (x -> unlines (reverse (lines x)))
可读性不强.但是,使用函数组合,您可以将其编写如下:
Not very readable. Using function composition however you could write it as follows:
main = interact (unlines . reverse . lines)
如您所见,函数组合非常有用,但您不能在任何地方使用它.例如,您不能使用函数组合将 filter
的输出通过管道传输到 length
中:
As you can see function composition is very useful but you can't use it everywhere. For example you can't pipe the output of filter
into length
using function composition:
countWhere = length . filter -- this is not allowed
不允许这样做的原因是 filter
的类型是 (a -> Bool) ->[a] ->[a]
.将它与 a -> 进行比较b
我们发现 a
的类型是 (a -> Bool)
而 b
的类型是 [a] ->[a]
.这会导致类型不匹配,因为 Haskell 期望 length
的类型为 b ->c
(即 ([a] -> [a]) -> c
).然而它实际上是 [a] ->Int
.
The reason this is not allowed is because filter
is of type (a -> Bool) -> [a] -> [a]
. Comparing it with a -> b
we find that a
is of type (a -> Bool)
and b
is of type [a] -> [a]
. This results in a type mismatch because Haskell expects length
to be of type b -> c
(i.e. ([a] -> [a]) -> c
). However it's actually of type [a] -> Int
.
解决方案非常简单:
countWhere f = length . filter f
然而,有些人不喜欢那种额外的悬垂f
.他们更喜欢在 countWhere>pointfree 样式如下:
However some people don't like that extra dangling f
. They prefer to write countWhere
in pointfree style as follows:
countWhere = (length .) . filter
他们是怎么得到这个的?考虑:
How do they get this? Consider:
countWhere f xs = length (filter f xs)
-- But `f x y` is `(f x) y`. Hence:
countWhere f xs = length ((filter f) xs)
-- But `x -> f (g x)` is `f . g`. Hence:
countWhere f = length . (filter f)
-- But `f . g` is `(f .) g`. Hence:
countWhere f = (length .) (filter f)
-- But `x -> f (g x)` is `f . g`. Hence:
countWhere = (length .) . filter
如你所见 (f .) .g
只是 x y ->f (g x y)
.这个概念其实可以迭代:
As you can see (f .) . g
is simply x y -> f (g x y)
. This concept can actually be iterated:
f . g --> x -> f (g x)
(f .) . g --> x y -> f (g x y)
((f .) .) . g --> x y z -> f (g x y z)
(((f .) .) .) . g --> w x y z -> f (g w x y z)
它不漂亮,但它完成了工作.给定两个函数,您还可以编写自己的函数组合运算符:
It's not pretty but it gets the job done. Given two functions you can also write your own function composition operators:
f .: g = (f .) . g
f .:: g = ((f .) .) . g
f .::: g = (((f .) .) .) . g
使用 (.:)
运算符,您可以将 countWhere
写成如下:
Using the (.:)
operator you could write countWhere
as follows instead:
countWhere = length .: filter
有趣的是,虽然你也可以用点自由风格编写 (.:)
:
Interestingly though you could write (.:)
in point free style as well:
f .: g = (f .) . g
-- But `f . g` is `(.) f g`. Hence:
f .: g = (.) (f .) g
-- But `x -> f x` is `f`. Hence:
(f .:) = (.) (f .)
-- But `(f .)` is `((.) f)`. Hence:
(f .:) = (.) ((.) f)
-- But `x -> f (g x)` is `f . g`. Hence:
(.:) = (.) . (.)
同样我们得到:
(.::) = (.) . (.) . (.)
(.:::) = (.) . (.) . (.) . (.)
如你所见,(.:)
、(.::)
和 (.:::)
只是 (.::)
的幂代码>(.)(即它们是(.) 的 > 迭代函数).对于数学中的数字:
As you can see (.:)
, (.::)
and (.:::)
are just powers of (.)
(i.e. they are iterated functions of (.)
). For numbers in Mathematics:
x ^ 0 = 1
x ^ n = x * x ^ (n - 1)
类似于数学中的函数:
f .^ 0 = id
f .^ n = f . (f .^ (n - 1))
如果 f
是 (.)
那么:
(.) .^ 1 = (.)
(.) .^ 2 = (.:)
(.) .^ 3 = (.::)
(.) .^ 4 = (.:::)
这让我们接近本文的结尾.对于最后的挑战,让我们以 pointfree 风格编写以下函数:
That brings us close to the end of this article. For a final challenge let's write the following function in pointfree style:
mf a b c = filter a (map b c)
mf a b c = filter a ((map b) c)
mf a b = filter a . (map b)
mf a b = (filter a .) (map b)
mf a = (filter a .) . map
mf a = (. map) (filter a .)
mf a = (. map) ((filter a) .)
mf a = (. map) ((.) (filter a))
mf a = ((. map) . (.)) (filter a)
mf = ((. map) . (.)) . filter
mf = (. map) . (.) . filter
我们可以进一步简化如下:
We can further simplify this as follows:
compose f g = (. f) . (.) . g
compose f g = ((. f) . (.)) . g
compose f g = (.) ((. f) . (.)) g
compose f = (.) ((. f) . (.))
compose f = (.) ((. (.)) (. f))
compose f = ((.) . (. (.))) (. f)
compose f = ((.) . (. (.))) (flip (.) f)
compose f = ((.) . (. (.))) ((flip (.)) f)
compose = ((.) . (. (.))) . (flip (.))
使用 compose
你现在可以将 mf
写成:
Using compose
you can now write mf
as:
mf = compose map filter
是的,它有点丑,但它也是一个非常棒的令人难以置信的概念.您现在可以编写任何形式为 x y z -> 的函数.f x (g y z)
作为 compose f g
非常简洁.
Yes it is a bit ugly but it's also a really awesome mind-boggling concept. You can now write any function of the form x y z -> f x (g y z)
as compose f g
and that is very neat.
这篇关于(f .) 有什么作用?g 在 Haskell 中是什么意思?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!