.

发布时间 2023-04-12 04:23:38作者: 牧羊龟

在Haskell中,用 . 函数来完成函数的组合,其定义如下

(.) :: (b -> c) -> (a -> b) -> a -> c
f . g = \ x -> f (g x)
  • f必须有一个与g的结果类型相同的值作为参数

函数组合的用途之一是动态地创建函数,并将其传递给其他函数。
当然,也可以使用Lambdas,但很多时候函数的组合更清晰、更简洁,如下

map (\ x negate (abs x)) [5, -3, -6.7, -3.2, -19.24]
map (negate.abs) [5, -3, -6.7, -3.2, -19.24]

函数的组合是向右结合的,所以可以同时组合几个函数。 f (g (z x))等价于(f.g.z) x,如下

map (\ xs -> negate (sum (tail xs))) [[1..5], [3..6], [1..7]]
map (negate . sum . tail) [[1..5], [3..6], [1..7]]

带有多个参数的函数,想使用函数组合,必须使用curry,让每个函数接受一个参数,如下

sum (replicate 5 (max 6.7 8.9))
(sum . replicate 5 . max 6.7) 8.9
sum. replicate 5 . max 6.7 $ 8.9

如果想要使用函数组合重写一个包含大量圆括号的表达式,可以先将最内层函数的最后一个形参放在$之后,然后开始组合所有其他函数
如下

replicate 100 (product (map (* 3) (zipWith max [1,2,3,4,5] [4,5,6,7,8])))
replicate 100 . product . map (* 3) . zipWith max [1,2,3,4,5] $ [4,5,6,7,8]

有时函数的组合更容易阅读,有时函数的组合不容易阅读
追求短代码可以使用函数的组合,想提升阅读性可以使用let in表达式,如下

oddSquareSum = sum (takeWhile (< 10000) (filter odd (map (^ 2) [1..])))

oddSquareSum = sum . takeWhile (< 10000) . filter odd . map (^ 2) $ [1..]

oddSquareSum = 
  let oddSquares = filter odd $ map (^ 2) [1..]
      belowLimit = takeWhile (< 10000) oddSquares
  in sum belowLimit