什么是(f。)。 g的意思是在Haskell中? [英] What does (f .) . g mean in Haskell?

查看:148
本文介绍了什么是(f。)。 g的意思是在Haskell中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经看到很多函数是根据(f。)模式定义的。克。例如:

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

这是什么意思?

What does this mean?

推荐答案

点运算符(即(。))是函数组合运算符。它的定义如下:

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 result of the second function to the first function).

函数组合运算符非常有用。它允许您将一个函数的输出传递到另一个函数的输入中。例如,您可以在Haskell中编写一个 tac 程序,如下所示:

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)

正如您所看到的,函数组合非常有用,但无法在任何地方使用。例如,你不能使用函数合成将过滤器的输出传递到长度中:

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

不允许的原因是因为过滤器的类型是(a - > Bool) - > [a] - > [α] 。将它与 a - >进行比较我们发现 a 的类型是(a - > Bool),而 b 类型为 [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.

解决方案非常简单:

The solution is pretty simple:

countWhere f = length . filter f

然而有些人不喜欢那种额外悬挂 f 。他们更愿意在点免费风格中编写 countWhere ,如下所示:

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:

(.:) = (.) . (.)

同样我们得到:

Similarly we get:

(.::)  = (.) . (.) . (.)
(.:::) = (.) . (.) . (.) . (.)

正如您所见(。:)(。::)(。:::)只是(即它们是迭代函数 ( 。))。对于数学中的数字:

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)

类似于数学中的函数:

Similarly for functions in Mathematics:

f .^ 0 = id
f .^ n = f . (f .^ (n - 1))

如果 f (。)然后:

If f is (.) then:

(.) .^ 1 = (.)
(.) .^ 2 = (.:)
(.) .^ 3 = (.::)
(.) .^ 4 = (.:::)

这使我们接近本文的结尾。对于最后的挑战,我们用无点式编写以下函数:

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 (.))

使用撰写您现在可以将 mf 写为:

Using compose you can now write mf as:

mf = compose map filter

是的,它有点丑,但它也是一个非常令人敬畏的令人难以置信的概念。您现在可以编写任何形式的函数 \ x y z - > f x(g y z)作为撰写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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆