patterns介绍
可以将定义函数行为的主题分离为几个部分,这样代码就更优雅、干净、易于阅读。如下
lucky :: ( Integral a ) => a -> String
lucky 1 = "one!"
lucky 3 = "three!"
lucky 5 = "five!"
lucky 7 = "seven!"
lucky x = "Sorry, it's not your lucky day!"
- 当调用lucky时,从上到下检查模式,当模式与相关值匹配时,执行相关的函数体
- 这种情况下,数字与第一个模式匹配的唯一方法是该数字为1。如果不是则顺序计算下一个模式
- 如果我们将最后一个模式移到开始,我们总会得到"Sorry, it's not your lucky day!",因为第一个模式可以匹配任何数字,并且不可能检查其他模式
- 定义模式时,顺序很重要,最好在开始定义最具体的模式,将通用的模式放在最后
- 必须包含一个通用的模式,避免程序失败
阶乘函数,如下
factorial :: ( Integral a ) => a -> a
factorial 0 = 1
factorial n = n * factorial ( n - 1 )
- 递归在Haskell中非常重要
Tuple模式
如下
addVectors :: Num a => (a, a) -> (a, a) -> (a, a)
addVectors (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)
first :: (a, b, c) -> a
first (x, _, _) = x
second :: (a, b, c) -> b
second (_, y, _) -> y
- 下划线与内涵列表中具有相同的含义,表示我们并不关心该值,因为不会使用它
内涵列表中使用模式
如下
xs = [(1.3), (4.3), (2.4), (5.3), (5.6), (3.1)]
[a + b | (a, b) <- xs]
[4,7,6,8,11,4]
List模式
- 像(x : xs)这样的模式会把列表的头部与x绑定,其余的元素与xs绑定,即使列表只有一个元素,这种情况下xs最终为空列表
- (x : xs)这样的模式被广泛使用,特别是在递归函数中
实现myHead函数,如下
myHead :: [a] -> a
myHead [] = error "an empty list~"
myHead (x : _) = x
- error函数接受一个字符串,并把字符串内容作为发生错误的信息生成一个运行时错误,它会导致程序结束,不适合经常使用
递归实现myLength函数和mySum函数,如下
myLength :: Num b => [a] -> b
myLength [] = 0
myLength (_ : xs) = 1 + myLength xs
mySum :: Num b => [a] -> b
mySum [] = 0
mySum (x : xs) = x + mySum xs
so-called模式
使用模式分解某些东西时,还可以保留对该东西的整体引用
- 在模式前面加 name @,@不能被空格包围。例如: xs@(x : y : ys)
- 这种模式和(x : y : ys)完全相同,但我们可以使用xs轻松访问整个list,如下
capital :: String -> String
capital [] = "An empty String~"
capital all@(x : _) = "The first letter of " ++ all ++ " is " ++ [x]