我正在阅读这篇关于Haskell的教程。他们将函数合成定义如下:
(.) :: (b->c) -> (a->b) -> (a->c)
f . g = \ x -> f (g x)
没有提供示例,我相信这会让我了解正在定义什么。
能否提供一个简单的例子(附有解释),说明如何使用函数组合?
我正在阅读这篇关于Haskell的教程。他们将函数合成定义如下:
(.) :: (b->c) -> (a->b) -> (a->c)
f . g = \ x -> f (g x)
没有提供示例,我相信这会让我了解正在定义什么。
能否提供一个简单的例子(附有解释),说明如何使用函数组合?
函数组合是将两个函数合并成一个函数的一种方法。以下是一个例子:
假设你有这些函数:
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]
更短,出错的空间更小。
有趣的一笔。函数组合在逻辑中相当于三段论:
所有人都是会死的。苏格拉底是个人。因此,苏格拉底会死。
三段论将两个材料蕴含式组合成一个:
(Man => Mortal), (Socrates => Man), therefore (Socrates => Mortal)
因此,我们需要在代码中添加一个条件语句,以便只有在特定情况下才会执行该行代码。
(b -> c) -> (a -> b) -> (a -> c)
...这是.
函数的类型。
f和g
的复合函数是一个函数,它首先将其参数应用于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)); }
sqr x = x * x
inc x = x + 1
我们希望编写一个计算x的平方加1的函数。我们可以这样编写:
xSquaredPlusOne = inc . sqr
(这意味着
xSquaredPlusOne x = (inc . sqr) x
xSquaredPlusOne x = inc(sqr x)
desort = (reverse . sort)
desort
是一个将列表按照相反顺序排序的函数。基本上,desort
将其参数传递给sort
,然后将sort
的返回值传递给reverse
,并返回它。因此,它首先对其进行排序,然后再将其反转。函数组合是将两个或多个函数链接在一起的一种方法。它通常被比喻为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
你基本上可以在任何其他函数可以使用的地方使用它。它只是一种快速和易读的方式,表示“我想把这些函数链接在一起”。
myOdd x = not . even x
? - unclerojeliomyOdd
不是通过给定参数的结果进行定义("给定x
,myOdd
的返回值与(not . even) x
相同"),而是在实际上是什么方面进行定义("myOdd
是将not
与even
组合得到的函数")。 - chepner