Functional Programming on Lists

map: transform [a] to [f(a)]

1
2
-- 函数签名
map :: (a -> b) -> [a] -> [b]

filter

1
filter :: (a -> Bool) -> [a] -> [a]
Utilities

words 可以把 String 按空格分割开来

tails 可以返回一个字符串的全部后缀

Partial Application

当一个参数传入函数,默认总是占据最左侧没被赋值的参数

Prefix and Infix Notations

每一个中缀形式的运算符都有等价形式的前缀形式,写法是用括号 () 包住运算符然后提前

1
2
3
1 + 2
-- 等价于……
(+) 1 2

zipWith

1
2
3
4
5
6
-- 函数签名
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]

-- 使用例
zipWith (+) [0,2,5] [1,4,7]
-- Result = [1, 6, 12]

Lambda Functions

定义一个匿名函数的方式如下

1
2
3
4
5
6
-- 反斜杠,用空格隔开的参数,->,函数体
\x y z -> x + y + z
\x -> x > 7

-- 使用例
filter (\x -> x > 7) [1, 10, 100]

. 运算符与 $ 运算符

点运算符

. 运算符将多个函数结合,类似于数学里面的记号

1
2
3
4
5
6
7
8
9
10
(.) :: (b -> c) -> (a -> b) -> a -> c

-- 考虑……
(f . g) x
-- 等价于
f (g x)

-- 使用例
third = head . tail . tail
-- fetches the third element of a list

美元运算符

1
2
3
4
5
6
($) :: (a -> b) -> a -> b

-- 即
f $ x
-- 等价于
f x

$ 的作用主要是用于消除函数嵌套时的括号:

1
2
3
4
5
6
f1 (f2 (f3 ...... (fn x)))
-- 用 $ 符号化简
f1 $ f2 $ f3 ...... $ fn x

-- 或者同时用 . 和 $ 化简
f1 . f2 . f3 ...... fn $ x

More Functions

takeWhile, dropWhile

takeWhile, dropWhliefilter 的区别在于,takeWhile, dropWhlie 其实是只考虑列表的前缀,而 filter 是过滤整个列表。

1
2
3
4
5
6
7
8
takeWhile :: (a -> Bool) -> [a] -> [a]
-- take elements from a list as long as they satisfy a predicate
dropWhile :: (a -> Bool) -> [a] -> [a]
-- drop elements from a list as long as they satisfy a predicate

-- 使用例
takeWhile even [2,4,1,2,3] -- ==> [2,4]
dropWhile even [2,4,1,2,3] -- ==> [1,2,3]

elem

检查元素是否在列表里面。

const

总是返回两个参数里的第一个参数

1
const :: a -> b -> a

Lists and Recursion

  1. 在列表头添加元素
1
2
3
4
(:) :: a -> [a] -> [a]

-- 使用例
1:[2,3]

Pattern Matching for Lists

1
2
3
4
[x:_] -- 提取列表第一个元素
f (_:x:_) = x -- 提取第二个元素
[x:y:_] -- 前两个元素
[x:y:z:_] -- 前三个元素

Tail Recursion

类似的,列表上的递归函数也可以应用尾递归


List Comprehension

和 Python 一样,Haskell 也有列表操作

1
2
3
4
5
6
7
[f x | x <- lis] -- <=> map f lis

[x | x <- lis, pred x] -- <=> filter pred lis

[f x | x <- lis, p x]
-- 等价于
map f (filter p lis)

同样支持其他操作

1
2
3
4
5
6
7
8
9
10
11
12
-- 多个列表
[ first ++ " " ++ last | first <- ["John", "Mary"], last <- ["Smith","Cooper"] ]
==> ["John Smith","John Cooper","Mary Smith","Mary Cooper"]

-- Local Definition
[ reversed | word <- ["this","is","a","string"], let reversed = reverse word ]
==> ["siht","si","a","gnirts"]

-- Pattern Matching
firstLetters string = [ char | (char:_) <- words string ]
firstLetters "Hello World!"
==> "HW"

自定义(中缀)运算符

Haskell 里的运算符定义只需要任意符号即可

1
2
3
-- For example
(<+>) :: [Int] -> [Int] -> [Int]
xs <+> ys = zipWith (+) xs ys

Typed Holes

类似于 C++ 的 auto,Haskell 可以自动推导 _<name> 的类型,但是会通过报错的形式告诉你

定义语法是:下划线 _ + 任意名字

1
2
3
4
5
keepElements :: [a] -> [Bool] -> [a]
keepElements xs bs = _doIt (zip xs bs)

-- <interactive>: error:
-- • Found hole: _doIt :: [(a, Bool)] -> [a]