Learn You a Haskell for Great Good

递归

• 递归求最大值
``````maximumVal :: (Ord a)=>[a]->a
maximumVal [] = error "error"
maximumVal [x] = x
maximumVal (x:xs)
| x > maxTail = x
| otherwise = maxTail
where maxTail = maximumVal xs
``````

``````maximum' :: (Ord a) => [a] -> a
maximum' [] = error "maximum of empty list"
maximum' [x] = x
maximum' (x:xs) = max x (maximum' xs)
``````
• 实现take
``````take' :: (Num i, Ord i) => i -> [a] -> [a]
take' n _
| n <= 0 = []
take' _ [] = []
take' n (x:xs) = x : take' (n-1) xs
``````
• 实现reverse
``````reverse' :: [a] -> [a]
reverse' [] = []
reverse' (x:xs) = reverse' xs ++ [x]
``````
• 实现zip
``````zip' :: [a] -> [b] -> [(a,b)]
zip' _ [] = []
zip' [] _ = []
zip' (x:xs) (y:ys) = (x,y):zip' xs ys
``````
• 快速排序
``````quicksort :: (Ord a) => [a] -> [a]
quicksort [] = []
quicksort (x:xs) =
let smallerSorted = quicksort [a | a <- xs, a <= x]
biggerSorted = quicksort [a | a <- xs, a > x]
in smallerSorted ++ [x] ++ biggerSorted
``````

高阶函数

``````f(x) = x^2
g(x) = 2x+1
f(g(x)) = (2x+1)^2 = 4x^2+4x+1
``````

• currying:

``````getMaxValue x  = max 4 5
``````

``````getMaxValue2 x = (max 4) 5
``````

``````multThree :: (Num a) => a -> a -> a -> a
multThree x y z = x * y * z
``````

``````(((multThree 3)5)9)
``````

``````compareWithHundred :: (Num a,Ord a) => a -> Ordering
compareWithHundred x = compare 100 x
``````

``````compareWithHundredWithoutX :: (Num a,Ord a) => a -> Ordering
compareWithHundredWithoutX = compare 100

applyTwice :: (a -> a) -> a -> a
applyTwice f x = f (f x)

``````

``````ghci> applyTwice (+3) 10
``````

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

``````

``````ghci> zipWith' (+) [4,2,5,6] [2,6,2,3]
[6,8,7,9]

``````

``````ghci> zipWith' max [6,3,2,1] [7,3,1,5]
[7,3,2,5]
ghci> zipWith' (++) ["foo "，"bar "，"baz "] ["fighters"，"hoppers"，"aldrin"]
["foo fighters","bar hoppers","baz aldrin"]
ghci> zipWith' (*) (replicate 5 2) [1..]
[2,4,6,8,10]
ghci> zipWith' (zipWith' (*)) [[1,2,3],[3,5,6],[2,3,4]] [[3,2,2],[3,4,5],[5,4,3]]
[[3,4,6],[9,20,30],[10,12,12]]

``````
• map：取一个函数和 List 做参数，遍历该 List 的每个元素来调用该函数产生一个新的 List。 看下它的类型声明和实现:
``````map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs

``````

``````ghci> map (+3) [1,5,3,1,6]
[4,8,6,4,9]

``````

filter：函数取一个限制条件和一个 List，回传该 List 中所有符合该条件的元素

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

ghci> filter (>3) [1,5,3,2,1,6,4,3,2,1]
[5,6,4]

``````

takeWhile 函数，它取一个限制条件和 List 作参数，然后从头开始遍历这一 List，并回传符合限制条件的元素

• lambda:就是匿名函数。有些时候我们需要传给高阶函数一个函数，而这函数我们只会用这一次，这就弄个特定功能的 lambda

``````map (+3) [1,6,3,2] 与 map (\x -> x+3) [1,6,3,2]

``````

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

``````
• fold : fold 取一个二元函数，一个初始值(我喜欢管它叫累加值)和一个需要折叠的 List。 这个二元函数有两个参数，即累加值和 List 的首项(或尾项)，回传值是新的累加值。 然后，以新的累加值和新的 List 首项调用该函数，如是继续。 到 List 遍历完毕时，只剩下一个累加值，也就是最终的结果。

``````sum' :: (Num a) => [a] -> a
sum' xs = foldl (\acc x -> acc + x) 0 xs

``````

acc是累加值 由于使用foldl，那么x是数组的第一个元素 0 是起始值 计算过程是拿数组的x和acc相加，作为新的x，然后递归

``````elem' :: (Eq a) => a -> [a] -> Bool
elem' y ys = foldl (\acc x -> if x == y then True else acc) False ys

``````

foldl1是fold的简化版，初始值默认为数组的第一个元素 上面求和的函数用foldl1实现如下：

``````sum1 xs = foldl1 (\acc x -> acc + x) xs

``````

``````foldl1 (+) [1,2,3]

``````

scanl 和 scanr 与 foldl 和 foldr 相似，只是它们会记录下累加值的所有状态到一个 List。 也有 scanl1 和 scanr1。

``````ghci> scanl (+) 0 [3,5,2,1]
[0,3,8,10,11]
ghci> scanr (+) 0 [3,5,2,1]
[11,8,3,1,0]

``````

``````val = map (\x -> negate (abs x)) [5,-3,-6,7,-3,2,-19,24]
[-5,-3,-6,-7,-3,-2,-19,-24]

``````

``````val2 = map (negate . abs) [5,-3,-6,7,-3,2,-19,24]

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

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

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

``````