软糖

Haskell 3 Function

Taking Notes from http://learnyouahaskell.com

Pattern matching

1
2
3
4
5
6
7
8
9
10
lucky :: (Integral a) => a -> String
lucky 7 = "LUCKY NUMBER SEVEN!"
lucky x = "Sorry, you're out of luck!"
factorial :: (Integral a) => a -> a
factorial 0 = 1
factorial n = n * factorial (n - 1)
addVectors :: (Num a) => (a, a) -> (b, b) -> (a, a)
addVectors (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)
1
2
3
head :: [a] -> a
head [] = error "Cannot call head on an empty list"
head (x:_) = x

你若要绑定多个变量(用 _ 也是如此),我们必须用括号将其括起
error 函数,它可以生成一个运行时错误

1
2
3
length :: (Num b) => [a] -> b
length [] = 0
length (_:xs) = 1 + length xs

‘as’ model

1
2
3
capital :: String -> String
capital "" = "Empty string, whoops!"
capital all@(x:xs) = "The first letter of " ++ all ++ " is " ++ [x]

Guards

类似if语句,更好的可读性

1
2
3
4
max' :: (Ord a) => a -> a -> a
max' a b
| a > b = a
| otherwise = b

1
2
3
4
5
6
7
8
myCompare :: (Ord a) => a -> a -> Ordering
a `myCompare` b
| a > b = GT
| a == b = EQ
| otherwise = LT
ghci> 3 `myCompare` 2
GT

通过 `,我们不仅可以以中缀形式调用函数,也可以在定义函数的时候使用它

Where

1
2
3
4
5
6
7
8
9
10
bmiTell :: (RealFloat a) => a -> a -> String
bmiTell weight height
| bmi <= skinny = "You're underweight, you emo, you!"
| bmi <= normal = "You're supposedly normal. Pffft, I bet you're ugly!"
| bmi <= fat = "You're fat! Lose some weight, fatty!"
| otherwise = "You're a whale, congratulations!"
where bmi = weight / height ^ 2
skinny = 18.5
normal = 25.0
fat = 30.0

pattern matching

1
2
where bmi = weight / height ^ 2
(skinny, normal, fat) = (18.5, 25.0, 30.0)

Another example

1
2
3
4
initials :: String -> String -> String
initials firstname lastname = [f] ++ ". " ++ [l] ++ "."
where (f:_) = firstname
(l:_) = lastname

Where binding function

where 绑定可以定义名字,也可以定义函数

1
2
3
calcBmis :: (RealFloat a) => [(a, a)] -> [a]
calcBmis xs = [bmi w h | (w, h) <- xs]
where bmi weight height = weight / height ^ 2

let

where 绑定是在函数底部定义名字,对包括所有 guard 在内的整个函数可见。let 绑定则是个 表达式,允许你在任何位置定义局部变量,而对不同的 guard 不可见

1
2
3
4
5
cylinder :: (RealFloat a) => a -> a -> a
cylinder r h =
let sideArea = 2 * pi * r * h
topArea = pi * r ^ 2
in sideArea + 2 * topArea

let [bindings] in [expressions]
在 let 中绑定的名字仅对 in 部分可见

作为表达式

1
2
3
4
ghci> 4 * (let a = 9 in a + 1) + 2
42
ghci> [let square x = x * x in (square 5, square 3, square 2)]
[(25, 9, 4)]

list comprehension

1
2
calcBmis :: (RealFloat a) => [(a, a)] -> [a]
calcBmis xs = [bmi | (w, h) <- xs, let bmi = w / h ^ 2, bmi >= 25.0]

Case expressions

pattern matching is syntax suger of case expr

1
2
3
4
case expression of pattern -> result
pattern -> result
pattern -> result
...
1
2
3
4
5
6
7
8
// pattern matching
head' :: [a] -> a
head' [] = error "No head for empty lists!"
head' (x:_) = x
head' :: [a] -> a
head' xs = case xs of [] -> error "No head for empty lists!"
(x:_) -> x