patterns 模式

发布时间 2023-04-06 09:12:19作者: 牧羊龟

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]