寻求函数组合的解释

40

我正在阅读这篇关于Haskell的教程。他们将函数合成定义如下:

(.)                     :: (b->c) -> (a->b) -> (a->c)
f . g                   = \ x -> f (g x)

没有提供示例,我相信这会让我了解正在定义什么。

能否提供一个简单的例子(附有解释),说明如何使用函数组合?

6个回答

61

函数组合是将两个函数合并成一个函数的一种方法。以下是一个例子:

假设你有这些函数:

even :: Int -> Bool
not :: Bool -> Bool

如果你想使用上述两种函数自定义一个名为myOdd :: Int -> Bool的函数,那么显而易见的做法如下:

myOdd :: Int -> Bool
myOdd x = not (even x)

但是使用函数组合可以更简洁地实现:

myOdd :: Int -> Bool
myOdd = not . even

myOdd函数的行为完全相同,但第二个函数是通过“粘合”两个函数而创建的。

这种情况下特别有用的一种场景是,消除需要显式lambda函数的需求。例如:

map (\x -> not (even x)) [1..9]

可以重写为:

map (not . even) [1..9]

更短,出错的空间更小。


1
为什么在参数定义中不需要显示输入参数?比如,为什么不写myOdd x = not . even x - unclerojelio
5
这被称为"点无风格"。myOdd 不是通过给定参数的结果进行定义("给定 xmyOdd 的返回值与 (not . even) x 相同"),而是在实际上是什么方面进行定义("myOdd 是将 noteven 组合得到的函数")。 - chepner

44

有趣的一笔。函数组合在逻辑中相当于三段论:

 

所有人都是会死的。苏格拉底是个人。因此,苏格拉底会死。

三段论将两个材料蕴含式组合成一个:

(Man => Mortal), (Socrates => Man), therefore (Socrates => Mortal)

因此,我们需要在代码中添加一个条件语句,以便只有在特定情况下才会执行该行代码。

(b -> c) -> (a -> b) -> (a -> c)

...这是.函数的类型。


17

fg复合函数是一个函数,它首先将其参数应用于g,然后将g返回的值应用于f,最后返回f的返回值。

这个等式可能很有启发性:

f (g x) = (f . g) x

如果你有Java/C的背景,可以考虑这个例子:

int f(int x);
int g(int x);
int theComposition(int x) { return f(g(x)); }

8
这个例子是虚构的,但假设我们有:
sqr x = x * x  
inc x = x + 1

我们希望编写一个计算x的平方加1的函数。我们可以这样编写:

xSquaredPlusOne = inc . sqr

(这意味着

xSquaredPlusOne x = (inc . sqr) x

这意味着。
xSquaredPlusOne x = inc(sqr x)

自从 f=inc 且 g=sqr,这段代码就一直在运行。

5

来自HaskellWiki的函数组合页面:

desort = (reverse . sort)

现在,desort是一个将列表按照相反顺序排序的函数。基本上,desort将其参数传递给sort,然后将sort的返回值传递给reverse,并返回它。因此,它首先对其进行排序,然后再将其反转。

5

函数组合是将两个或多个函数链接在一起的一种方法。它通常被比喻为shell管道。例如,在类 Unix shell 中,您可能会编写类似以下的代码:

cat foo.txt | sort -n | less

这个命令运行cat,将其输出传递给sort,再将其输出传递给less

严格来说,这就像Haskell中的$操作符。你可以写成这样:

sum $ sort $ filter (> 0) $ my_list

请注意,与shell示例不同,这个示例从右到左读取。所以我们从输入的my_list开始,然后运行filter,然后对其进行sort,最后计算出它的sum

函数组合运算符.也执行类似操作。上面的示例产生一个数字;下面的示例则产生一个函数

sum . sort . filter (> 0)

请注意,我们实际上并没有将列表输入到其中。相反,我们只是创建了一个新函数,可以将多个不同的列表输入到该函数中。例如,您可以为此函数命名:
my_function = sum . sort . filter (> 0)

或者您可以将它作为参数传递给另一个函数:

map (sum . sort . filter (> 0)) my_lists

你基本上可以在任何其他函数可以使用的地方使用它。它只是一种快速和易读的方式,表示“我想把这些函数链接在一起”。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接