Function Haskell函数组合

Function Haskell函数组合,function,haskell,functional-programming,composition,Function,Haskell,Functional Programming,Composition,我正在读哈斯克尔的教程。它们将功能组合定义为以下内容: (.) :: (b->c) -> (a->b) -> (a->c) f . g = \ x -> f (g x) myOdd :: Int -> Bool myOdd x = not (even x) 没有提供任何例子,我相信这些例子会启发我这里的定义 有人能提供一个简单的例子(带解释)说明函数组合是如何使用的吗?f和g

我正在读哈斯克尔的教程。它们将功能组合定义为以下内容:

(.)                     :: (b->c) -> (a->b) -> (a->c)
f . g                   = \ x -> f (g x)
myOdd :: Int -> Bool
myOdd x = not (even x)
没有提供任何例子,我相信这些例子会启发我这里的定义

有人能提供一个简单的例子(带解释)说明函数组合是如何使用的吗?

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

这一身份可能具有启发性:

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

如果你有爪哇/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^2+1的函数。我们可以写作

xSquaredPlusOne = inc . sqr
(这意味着

xSquaredPlusOne x = (inc . sqr) x
xSquaredPlusOne x = inc(sqr x)
也就是说

xSquaredPlusOne x = (inc . sqr) x
xSquaredPlusOne x = inc(sqr x)

因为f=inc和g=sqr)

函数组合是将两个函数“组合”为一个函数的方法。下面是一个例子:

假设您具有以下功能:

even :: Int -> Bool
not :: Bool -> Bool
您需要使用上述两个函数定义自己的
myOdd::Int->Bool
函数

显而易见的方法是:

(.)                     :: (b->c) -> (a->b) -> (a->c)
f . g                   = \ x -> f (g x)
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)

。。。这是
函数的类型。

函数组合是将两个或多个函数链接在一起的一种方法。它经常被比作壳牌管道。例如,在Unix样式的shell中,您可以编写如下内容

cat foo.txt | sort -n | less
sum $ sort $ filter (> 0) $ my_list
这将运行
cat
,将其输出馈送到
sort
,并将其输出馈送到
less

严格来说,这类似于Haskell
$
操作符。你可能会写这样的东西

cat foo.txt | sort -n | less
sum $ sort $ filter (> 0) $ my_list
请注意,与shell示例不同,它从右向左读取。因此,我们首先以
my_list
作为输入,然后对其运行
filter
,然后对其进行
sort
排序,然后计算其
sum

函数组合运算符
,执行类似的操作。上面的例子产生了一个数字;下面的示例生成一个函数:

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

my_function = sum . sort . filter (> 0)
map (sum . sort . filter (> 0)) my_lists
或者您可以将其作为参数传递给另一个函数:

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

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

为什么不需要在定义中显示输入参数?例如。你为什么不写
myodx=not。即使是x,它也被称为无点风格。与其根据给定参数的结果定义
myOdd
(“给定
x
myOdd
返回与
(not.event)x
)相同的值,
myOdd
是根据实际情况定义的(
myOdd
是当
not
偶数
组成时产生的函数)。