系列文章數組
一個函數知足如下任一條件即爲高階函數app
《計算的本質》講得更好一些,我感受這本書這裏講得不通透。ide
讓函數只接受一個參數就夠了。 若是想接受兩個參數,就先接受一個,返回一個接受另外一個參數的函數便可。函數
multThree :: Int -> Int -> Int -> Int -- 等價於 Int -> (Int -> (Int -> Int))
multThree x y z = x * y * z
複製代碼
divideByTen :: (Floating a) => a -> a
divideByTen = (/10) -- 這就是截斷
isUpperAlphanum :: Char -> Bool
isUpperAlphanum = (`elem` ['A'..' Z']) -- 這就是截斷
複製代碼
一個須要注意的問題是 (-4)
不能表示截斷,必須換成 (`subtract` 4)
工具
applyTwice :: (a -> a) -> a -> a -- 注意這裏的括號不能省略
applyTwice f x = f (f x)
複製代碼
注意這裏的括號不能省略,由於 -> 默認是右結合。post
技巧:在編寫函數(尤爲是高階函數)時若是拿不許函數的類型,能夠先不寫函數的類型聲明,定義完畢後再利用 :t 查看 Haskell 推導出的結果。spa
ghci> map (++ "!") ["BIFF"," BANG"," POW"]
["BIFF!"," BANG!"," POW!"]
ghci> filter even [1.. 10]
[2, 4, 6, 8, 10]
ghci> let listOfFuns = map (*) [0..]
ghci> (listOfFuns !! 4) 5
20
複製代碼
lambda 就是一次性的匿名函數。寫法是\param1 param2 -> returnValue
,必要的時候能夠用圓括號括起來。3d
若是參數是二元組,應該怎麼聲明 lambda:code
ghci> map (\(a, b) -> a + b) [(1, 2),( 3, 5)] -- 注意這裏的 (a,b) 是模式匹配,不是兩個參數
[3, 8]
複製代碼
如下例子說明 Haskell 的函數是默認柯里化的ip
addThree :: Int -> Int -> Int -> Int
addThree x y z = x + y + z
addThree' :: Int -> Int -> Int -> Int
addThree' = \x -> \y -> \z -> x + y + z
-- 上面倆函數等價
flip1 :: (a -> b -> c) -> b -> a -> c
flip1 f y x = f x y
flip2 :: (a -> b -> c) -> b -> a -> c
flip2 f = \y x -> f x y
-- 上面倆函數等價
複製代碼
foldl (\acc x -> acc + x) init list
foldr (\x acc -> x : acc) init list
foldl1 step list -- 第一個元素就是 init
foldr1 step list -- 第一個元素就是 init
複製代碼
另外一種方式理解摺疊:摺疊就是對列表中的全部元素連續地應用某個函數。如:
foldr f 0 [1,2,3,4]
-- 其實就是
f 1 (f 2 (f 3 (f 4 0)))
foldl g 0 [1,2,3,4]
-- 其實就是
g (g (g (g 0 1) 2) 3) 4
複製代碼
當二元函數 f 不老是須要對第二個參數求值時,便可經過 foldr 對無限列表作處理。fordl 則不行。
scan 與 fold 相似,區別在於 scan 會把每一次 step 的返回值記錄在一個列表裏。
後面的是函數的參數,相似 JS 的 .call。
sum $ filter (> 10) $ map (*2) [2.. 10] -- 獲得 80
sum (filter (> 10) (map (*2) [2.. 10])) -- 若是不用 $ 就要加不少括號
ghci> map ($ 3) [(4+),( 10*),(^ 2), sqrt]
[7. 0, 30. 0, 9. 0, 1. 7320508075688772]
複製代碼
數學定義:(f·g)(x) = f(g(x))
,它的目的是方便生成新函數。
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
複製代碼
技巧:若是你打算用組合來省去大量括號,能夠先找出最裏面的函數和參數,寫下來,在前面加一個 前面,如
replicate 2 (product (map (*3) (zipWith max [1, 2] [4, 5])))
-- 改寫爲
replicate 2 . product . map (*3) $ zipWith max [1, 2] [4, 5]
複製代碼
若是你發現函數定義裏出現
fn x = fn2 p1 x
那麼你能夠直接簡化成
fn = fn2 p1
這一點在《計算的本質》也講到了。
這樣寫的好處是,簡潔。