• 高阶函数就是以函数为参数或者返回值的函数。
  • 柯里函数
  • lambda 函数
  • map, filter
compareWithHundred :: Int -> Ordering
compareWithHundred = compare 100

divideByTen :: (Floating a) => a -> a
divideByTen = (/10)

dividedByTen :: (Floating a) => a -> a
dividedByTen = (10/)

zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' _ [] _ = []
zipWith' _ _ [] = []
zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys

flip' :: (a -> b -> c) -> b -> a -> c
flip' f y x = f x y

map' :: (a -> b) -> [a] -> [b]
map' _ []     = []
map' f (x:xs) = f x : map' f xs

filter' :: (a -> Bool) -> [a] -> [a]
filter' _ []    = []
filter' p (x:xs)
    | p x       = x : filter' p xs
    | otherwise = filter' p xs

quicksort :: (Ord a) => [a] -> [a]
quicksort [] = []
quicksort (x:xs) = 
    let le = filter (<=x) xs
        gt = filter (> x) xs
    in quicksort le ++ [x] ++ quicksort gt

takeWhile' :: (a -> Bool) -> [a] -> [a]
takeWhile' _ [] = []
takeWhile' p (x:xs)
    | p x       = x : takeWhile' p xs
    | otherwise = []


zipWith (\a b -> (a*30+3)/b) [5,4..1] [1..5]   -- [153.0,61.5,31.0,15.75,6.6]
map (\(a, b) -> a+b) [(1,2), (3,5), (6,2), (2,6), (2,5)]   -- [3,8,8,8,7]

addThree :: Int -> Int -> Int -> Int
addThree x y z = x + y + z

addThree' :: Int -> Int -> Int -> Int
addThree' = \x -> \y -> \z -> x + y + z

flip'' :: (a -> b -> c) -> b -> a -> c
flip'' f = \x y -> f y x
  • foldl
    • foldl 从列表的左端开始折叠,用初始值和列表的头部调用二元函数,得到一个新的累加值,并用新的累加值与列表的下一个元素调用二元函数,以此类推。
    • foldl 的二元函数,第一个参数是累计值,第二个参数是当前列表值
    • foldl f w [x y z] -- f (f (f w x) y) z
  • foldr
    • foldr 从列表的有段开始折叠
    • foldr 的二元函数,第一个参数是当前列表值,第二个参数是累计值
    • foldr f w [x y z] -- f x (f y (f z w))
    • foldr 可以用来处理无限长度列表
    • 需要生成新列表的时候,一般倾向于使用 foldr
  • foldl1, foldr1
    • foldl1, foldr1foldl, foldr 相似,只是无须明确提供初始值。它们假定列表的第一个(最后一个)元素为初始值。
  • scanl, scanr, scanl1, scanr1 和上述函数类似,只是保存了每次累加值的变动
sum' :: (Num a) => [a] -> a
sum' xs = foldl (+) 0 xs
-- equal to: sum' xs = foldl (\acc x -> acc + x) 0 xs

map' :: (a -> b) -> [a] -> [b]
map' f xs = foldr (\x acc -> f x : acc) [] xs
-- Less efficient: map' f xs = foldl (\acc x -> acc ++ [f x]) [] xs

reverse' :: [a] -> [a]
reverse' = foldl (\acc x -> x : acc) []
-- equal to: reverse' = foldl (flip (:)) []

product' :: (Num a) => [a] -> a
product' = foldl (*) 1

foldl (-) 0 [1,2,3,4,5] -- -15 = ((((0-1)-2)-3)-4)-5
foldr (-) 0 [1,2,3,4,5] -- 3   = 1-(2-(3-(4-(5-0))))

and' :: [Bool] -> Bool
and' xs = foldr (&&) True xs

and (repeat False) -- False = False && (False && (False && ...))

maximum' :: (Ord a) => [a] -> a
maximum' = foldl1 max

scanl (-) 0 [1,2,3,4,5]  -- [0,-1,-3,-6,-10,-15]
scanr (-) 0 [1,2,3,4,5]  -- [3,-2,4,-1,5,0]
  • $ 成为函数应用符
  • $ 优先级最低,空格的函数调用是左结合的, $ 是右结合的
  • $ 可将函数应用转为函数
  • . 称为函数组合
  • . 右结合
  • Point-Free 风格
($) :: (a -> b) -> a -> b
f $ x = f x

sum (filter (> 10) (map (*2) [2..10]))  -- 80
sum $ filter (> 10) (map (*2) [2..10])  -- 80
sum $ filter (> 10) $ map (*2) [2..10]  -- 80

map ($ 3) [(4+), (10*), (^2), sqrt]     -- [7.0,30.0,9.0,1.732050807569]

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

map (\x -> negate (abs x)) [5,-3,-6,7]  -- [-5,-3,-6,-7]
map (negate . abs) [5,-3,-6,7]          -- [-5,-3,-6,-7]

map (negate . sum . tail) [[1..5],[3..6],[1..7]] -- [-14,-15,-27]

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

replicate 2 (product (map (*3) (zipWith max [1,2] [4,5]))) -- [180,180]
replicate 2 . product . map (*3) $ zipWith max [1,2] [4,5] -- [180,180]

fn x = ceiling (negate (tan (cos (max 50 x))))
fn' = ceiling . negate . tan . cos . max 50

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

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