高阶函数


In [1]:
-- haskell函数只能接收一个参数,多参数函数使用柯里化实现
max 4 5


5

In [2]:
(max 4) 5


Redundant bracket
Found:
(max 4) 5
Why Not:
max 4 5
5

In [3]:
:t max


max :: forall a. Ord a => a -> a -> a

In [4]:
multithree :: Int -> Int -> Int -> Int
multithree x y z = x * y * z

In [5]:
-- equals
multithree 3 5 9


135

In [6]:
((multithree 3) 5) 9


Redundant bracket
Found:
((multithree 3) 5) 9
Why Not:
(multithree 3) 5 9
Redundant bracket
Found:
(multithree 3) 5
Why Not:
multithree 3 5
135

In [7]:
-- 返回一个函数,类似python partial
let multTwoWithNine = multithree 9

In [8]:
multTwoWithNine 2 3


54

In [10]:
compareWithHundred :: Int -> Ordering
compareWithHundred x = compare 100 x

In [11]:
compareWithHundred 99


GT

In [13]:
-- equals above
compareWithHundred :: Int -> Ordering
compareWithHundred = compare 100

In [14]:
compareWithHundred 89


GT

In [15]:
-- 通过截断对中缀函数部分应用
divideByTen :: (Floating a) => a -> a
divideByTen = (/10)

In [16]:
divideByTen 200


20.0

In [17]:
(/10) 200


20.0

In [18]:
-- -需要使用subtract替代
(subtract 4) 5


Redundant bracket
Found:
(subtract 4) 5
Why Not:
subtract 4 5
1

In [19]:
-- 打印函数, 默认函数不支持Show, 打印回报错
-- this would raise
-- multithree 4 3

In [21]:
-- 接收函数的函数
applyTwice :: (a -> a) -> a -> a
applyTwice f x = f (f x)

In [22]:
applyTwice (+3) 10


16

In [23]:
applyTwice (++ " HAHA") "HEY"


"HEY HAHA HAHA"

In [24]:
applyTwice (3:) [1]


[3,3,1]

In [30]:
-- 实现zipwith
zipwith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipwith' _ [] _ = []
zipwith' _ _ [] = []
zipwith' f (x:xs) (y:ys) = f x y : zipwith' f xs ys

In [31]:
zipwith' (+) [4, 2, 5, 6] [2, 6, 2, 3]


[6,8,7,9]

In [32]:
zipwith' max [6, 3, 2, 1] [7, 3, 1]


[7,3,2]

In [34]:
zipwith' (*) (replicate 5 2) [1..]


[2,4,6,8,10]

In [35]:
-- 实现flip
flip' :: (a -> b -> c) -> (b -> a -> c)
flip' f = g
    where g x y = f y x

In [36]:
-- same as above
flip' f x y = f y x

In [37]:
zip [1..5] "hello"


[(1,'h'),(2,'e'),(3,'l'),(4,'l'),(5,'o')]

In [39]:
flip' zip [1..5] "hello"


[('h',1),('e',2),('l',3),('l',4),('o',5)]

In [40]:
zipWith div [2, 2..] [10, 8, 6, 4, 2]


[0,0,0,0,1]

In [41]:
zipWith (flip' div) [2, 2..] [10,8..2]


[5,4,3,2,1]

In [42]:
-- 函数式编程工具箱
-- map函数
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x: map f xs

In [43]:
map (+3) [1,5,1,3,1,6]


[4,8,4,6,4,9]

In [45]:
map (++ "!") ["BIFE", "BANS", "BANG", "POW"]


["BIFE!","BANS!","BANG!","POW!"]

In [46]:
map (replicate 3) [3..6]


[[3,3,3],[4,4,4],[5,5,5],[6,6,6]]

In [48]:
map (map (^2)) [[1, 2], [3, 4, 5, 6], [7, 8]]


[[1,4],[9,16,25,36],[49,64]]

In [50]:
map fst [(1, 2), (3, 5), (6, 3), (2, 6), (2, 5)]


[1,3,6,2,2]

In [52]:
-- fliter函数
filter :: (a -> Bool) -> [a] -> [a]
filter _ [] = []
filter p (x:xs)
    | p x = x : filter p xs
    | otherwise = filter p xs

In [54]:
filter (>3) [1, 5, 3, 2, 1, 6, 4, 3, 2, 1]


[5,6,4]

In [55]:
filter (==3) [1..5]


[3]

In [56]:
filter even [1..10]


[2,4,6,8,10]

In [57]:
let notNull x = not (null x) in filter notNull [[1, 2, 3], [], [3,4,5], [2, 2], [], [], []]


[[1,2,3],[3,4,5],[2,2]]

In [58]:
filter (`elem` ['a'..'z']) "u LaUgH aT mE BeCaUsE I aM diFfeRent"


"uagameasadifeent"

In [59]:
filter (`elem` ['A'..'Z']) "i LaUgH aT mE BeCaUsE I aM"


"LUHTEBCUEIM"

In [60]:
-- 列表推导有时更好用
filter (< 15)  (filter even [1..20])


[2,4,6,8,10,12,14]

In [61]:
[x | x <- [1..20], x < 15, even x]


[2,4,6,8,10,12,14]

In [65]:
quicksort :: (Ord a) => [a] -> [a]
quicksort [] = []
quicksort (x:xs) =
    let smaller = filter (<= x) xs
        larger = filter (> x) xs
    in quicksort smaller ++ [x] ++ quicksort larger

In [68]:
-- more `map` and `filter`
largestDivible :: Integer
largestDivible = head (filter p [100000, 99999..])
    where p x = x `mod` 3829 == 0

In [70]:
takeWhile (/=' ') "elephants know how to party"


"elephants"

In [71]:
sum (takeWhile (<10000) (filter odd (map (^2) [1..])))


166650

In [72]:
-- same as above
sum (takeWhile (<10000) [m | m<- [n^2 | n<- [1..]], odd m])


166650

In [75]:
-- 克拉数
chain :: Integer -> [Integer]
chain 1 = [1]
chain n
    | even n = n:chain (n `div` 2)
    | odd n = n:chain (n*3 + 1)

In [76]:
chain 10


[10,5,16,8,4,2,1]

In [77]:
chain 1


[1]

In [78]:
chain 30


[30,15,46,23,70,35,106,53,160,80,40,20,10,5,16,8,4,2,1]

In [79]:
let listOfFuns = map (*) [0..]
(listOfFuns !! 4) 5


20

In [81]:
-- lambda 匿名函数
numLongChains :: Int
numLongChains = length (filter (\xs -> length xs > 15) (map chain [1..100]))

In [82]:
map (+3) [1,6,3,2]


[4,9,6,5]

In [83]:
map (\x -> x + 3) [1, 6,3,2]


Avoid lambda
Found:
\ x -> x + 3
Why Not:
(+ 3)
[4,9,6,5]

In [85]:
zipWith (\a b -> (a * 30 + 3) / b) [5, 4, 3, 2, 1] [1,2,3,4,5]


[153.0,61.5,31.0,15.75,6.6]

In [86]:
map (\(a, b) -> a + b) [(1, 2), (3, 5), (6, 3), (2, 6), (2, 5)]


Use uncurry
Found:
\ (a, b) -> a + b
Why Not:
uncurry (+)
[3,8,9,8,7]

In [87]:
addThree :: Int -> Int -> Int -> Int
addThree x y z = x + y + z

In [88]:
addThree' :: Int -> Int -> Int -> Int
addThree' = \x -> \y -> \z -> x + y + z

In [89]:
flip' :: (a -> b -> c) -> b -> a -> c
flip' f = \x y -> f y x

In [90]:
zipWith (flip (++)) ["love you", "love me"] ["i ", "you "]


["i love you","you love me"]

In [92]:
map (flip subtract 20) [1, 2, 3, 4]


Use section
Found:
(flip subtract 20)
Why Not:
(`subtract` 20)
[19,18,17,16]

In [93]:
-- 折叠fold
sum' :: (Num a) => [a] -> a
sum' xs = foldl (\acc x -> acc + x) 0 xs

In [94]:
sum' [3, 5, 2,1]


11

In [95]:
-- same as above
sum' :: (Num a) => [a] -> a
sum' = foldl (+) 0

In [96]:
sum' [3..7]


25

In [97]:
-- fold right
map' :: (a -> b) -> [a] -> [b]
map' f xs = foldr (\x acc -> f x : acc ) [] xs

In [98]:
map' (+3) [1,2,3]


[4,5,6]

In [99]:
-- fold left
map' :: (a -> b) -> [a] -> [b]
map' f xs = foldl (\acc x -> acc ++ [f x]) [] xs

In [100]:
map' (+3) [1, 2, 3]


[4,5,6]

In [101]:
-- 生成列表有右fold更好
-- 左折叠无法处理无限列表,右折叠可以
elem' :: (Eq a) => a -> [a] -> Bool
elem' y ys = foldr (\x acc -> if x == y then True else acc) False ys

In [103]:
elem' False [False, True]


True

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

In [106]:
-- fold reverse
reverse' :: [a] -> [a]
reverse' = foldl (\acc x -> x : acc) []

In [107]:
reverse' [1..5]


[5,4,3,2,1]

In [108]:
reverse' :: [a] -> [a]
reverse' = foldl (flip (:)) []

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

In [110]:
product' [1..5]


120

In [111]:
filter' :: (a -> Bool) -> [a] -> [a]
filter' p = foldr (\x acc -> if p x then x : acc else acc) []

In [112]:
filter' (>3) [1..5]


[4,5]

In [114]:
last' :: [a] -> a
last' = foldl1 (\_ x -> x)

In [115]:
last' [1..5]


5

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

In [118]:
and' [True, False, True]


False

In [119]:
and' (repeat False)


False

In [120]:
-- 扫描scan, 跟踪fold实现过程
scanl (+) 0 [3,5,2,1]


[0,3,8,10,11]

In [121]:
scanr (+) 0 [3, 5,2,1]


[11,8,3,1,0]

In [122]:
-- scan to see over fold
sqrtSums :: Int
sqrtSums = length (takeWhile (<1000) (scanl1 (+) (map sqrt [1..]))) + 1

In [123]:
sqrtSums


131

In [132]:
sqrtSums :: [Float]
sqrtSums = takeWhile (<1000) (scanl1 (+) (map sqrt [1..]))

In [133]:
sqrtSums


[1.0,2.4142137,4.1462646,6.1462646,8.382333,10.831822,13.477573,16.306,19.306,22.468277,25.784903,29.249004,32.854557,36.596214,40.469196,44.469196,48.5923,52.83494,57.19384,61.665977,66.24855,70.938965,75.734795,80.63377,85.63377,90.732796,95.92895,101.22045,106.60561,112.08284,117.650604,123.30746,129.05202,134.88297,140.79904,146.79904,152.8818,159.04622,165.29121,171.61577,178.01889,184.49963,191.05707,197.69032,204.39853,211.18086,218.03651,224.96472,231.96472,239.0358,246.17723,253.38834,260.66846,268.01694,275.43314,282.91644,290.46628,298.08206,305.7632,313.5092,321.31943,329.19342,337.13068,345.13068,353.19293,361.31696,369.50232,377.74854,386.05515,394.42175,402.8479,411.3332,419.8772,428.47952,437.13977,445.85757,454.63254,463.4643,472.35248,481.29675,490.29675,499.35214,508.4626,517.62775,526.8473,536.1209,545.4483,554.82916,564.2631,573.74994,583.2893,592.881,602.52466,612.22003,621.9668,631.7648,641.61365,651.5131,661.463,671.463,681.5129,691.61237,701.7612,711.9593,722.20624,732.5019,742.84595,753.2383,763.6786,774.1667,784.70233,795.28534,805.91547,816.5925,827.31635,838.0867,848.9033,859.7661,870.6748,881.6293,892.6293,903.6746,914.76514,925.90063,937.081,948.30597,959.5754,970.8891,982.2469,993.6486]

In [135]:
-- 函数应用符号 $
($) :: (a -> b) -> a -> b
f $ x = f x

In [136]:
sqrt 3 + 4 + 9


14.732050807568877

In [137]:
sqrt $ 3  + 4 + 9


14.732050807568877

In [138]:
sum (filter (> 10) (map (*2) [2..10]))


80

In [139]:
sum $ filter (>10) (map (*2) [2..10])


80

In [141]:
-- good usage。 函数是同类型
map ($ 3) [(4+), (10*), (^2), sqrt]


[7.0,30.0,9.0,1.7320508075688772]

In [143]:
-- 函数组合,用来生产新函数
(.) :: (b -> c) -> (a -> b) -> a -> c
f . g = \x -> f (g x)

In [146]:
map (\x -> negate (abs x)) [5,-3,-6,7,-3,12,-19,24]


Avoid lambda
Found:
\ x -> negate (abs x)
Why Not:
negate . abs
[-5,-3,-6,-7,-3,-12,-19,-24]

In [147]:
map (negate . abs) [5,-3,-6,7,-3,12,-19,24]


[-5,-3,-6,-7,-3,-12,-19,-24]

In [149]:
map (negate . sum . tail) [[1..5], [3..6], [1..7]]


[-14,-15,-27]

In [151]:
-- 多参数函数组合, 通过部分应用转化为单参数函数
sum (replicate 5 (max 6.7 8.9))


44.5

In [153]:
(sum . replicate 5) (max 6.7 8.9)


44.5
getCurrentDirectory: resource exhausted (Too many open files)

In [154]:
-- pointless 风格
fn x = ceiling (negate (tan (cos ( max 50 x))))


getCurrentDirectory: resource exhausted (Too many open files)

In [4]:
fn = ceiling . negate . tan . cos . max


Non type-variable argument in the constraint: Floating (a -> a)
(Use FlexibleContexts to permit this)
When checking that ‘IHaskell25.fn’ has the inferred type
interactive:IHaskell25.fn :: forall c a. (Floating (a -> a), Integral c, Ord a, RealFrac (a -> a)) => a -> c

In [3]:
-- 不推荐过程的pointless风格代码。推荐使用let保存中间结果