Haskell 笔记 (四) 函数

本文深入探讨Haskell中的模式匹配技术,包括模式匹配的基本概念、元祖与列表的模式匹配、哨位Guard的使用、where关键字的作用以及case表达式的应用。通过具体示例展示了如何在函数定义中有效利用这些特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

haskell 函数

模式

模式匹配

模式匹配就是通过检查数据的特定结构来检查是否匹配,并按模式从中解析出数据

定义函数时可以定义多个不同模式,调用时会按照从上到下依次匹配,匹配成功则调用相应的函数体。

万能模式:模式中给出一个小写字母的名字,而非具体的值,将会总能匹配输入,称为万能模式。

注意:

  1. 多个匹配模式都满足时,只会匹配到第一个满足的模式。定义模式的顺序很重要。
  2. 一点要定义一个万能模式,防止意外输入导致崩溃。

例子:showName.hs

showName :: Int -> String
showName 1 = "Sam"                --模式1
showName 2 = "Joe"                --模式2   
showName 3 = "Tim"                --模式3
showName x = "Unknown Name"       --万能模式 
*Main> :load showName.hs
[1 of 1] Compiling Main             ( showName.hs, interpreted )
Ok, one module loaded.
*Main>
*Main>
*Main> showName 1
"Sam"
*Main> showName 2
"Joe"
*Main> showName 3
"Tim"
*Main> showName 4
"Unknown Name"

模式匹配方式完全可以使用 if 实现,但模式匹配方式更简洁。
不同的模式可以理解为不同子处理函数,匹配是从上到下,只有第一个匹配的模式可以被执行。

元祖的模式匹配

元祖的模式匹配是通过对元祖各项赋予名字(first, second, third, …), 即可以通过名字匹配到元祖各项。
对于不关心的元祖项可以通过下划线“_”忽略,如(_, _, third, …).

列表与列表推导式的模式匹配

推导式列表模式匹配

Prelude> let xs = [(1,2),(3,4),(5,6), (7,7),(8,9)]
Prelude> [a + b | (a, b) <- xs]
[3,7,11,14,17]

列表的模式匹配
[] 匹配空列表
:[]匹配非空列表, [1, 2, 3] 等价于 1:2:3:[]

x:xs模式在Haskell应用很广泛,它将列表头元素绑定到x, 余下部分绑定xs。 如果列表只有一个元素,那么xs将是一个空列表。

as模式

as模式允许按模式将值分为多个项,同时保留对整体的引用。格式为: 名字@模式

定义

firstLetter :: String -> String
firstLetter "" = "Empty"
firstLetter all@(x:xs) = "The first letter of " ++ all ++ " is " ++ [x]  --(x:xs)分解的参数

执行

firstLetter "Hashell"
"The first letter of Hashell is H"

哨位 Guard

Guard用来检测参数的值,和其他语言if类似。 Guard跟在“|”的右边。
Guard是一个布尔表达式的值。为True就执行相应的函数体。

注意: 每条Guard至少缩进1个空格,建议缩进4个空格,更容易阅读

showScore :: Int -> String
showScore score
     | score <= 10 = "0 ~ 10 "
     | score <= 50 = "11 ~ 50 " 
     | score <= 100 = "51 ~ 100 "
     | otherwise = "score error"        --otherwise,捕获一切未处理的条件

执行

showScore 7
"0 ~ 10 "
*Main> showScore 11
"11 ~ 50 "
*Main> showScore 80
"51 ~ 100 "
*Main> showScore 110
"score error"

和模式比较像,区别在与模式是对参数的结构匹配解析值,Guard是对参数值的检查

where

where 关键字用来保存中间结果。 可以减少重复计算提升可读性

showScore :: Int -> String
showScore score
     | doubleScore <= lowScore = "0 ~ 10 "
     | doubleScore <= midScore = "11 ~ 50 " 
     | doubleScore <= highScore = "51 ~ 100 "
     | otherwise = "score error"
     where doubleScore = score * 2      --doubleScore保存计算值,前面的Guard都可以使用,减少重复计算
           lowScore = 10                --通过对值的命名,提升可读性
           midScore = 50                --通过对值的命名,提升可读性  
           highScore = 100              --通过对值的命名,提升可读性

注意: where 定义的所有变量的起始必须对齐在同一列。

执行

*Main> showScore 3        
"0 ~ 10 "
*Main> showScore 6
"11 ~ 50 "
*Main> showScore 50
"51 ~ 100 "
*Main> showScore 51
"score error

另外where中也可以使用模式匹配, 还可以定义函数

showScore :: Int -> String
showScore score
     | doubleScore score <= lowScore = "0 ~ 10 "
     | doubleScore score <= midScore = "11 ~ 50 " 
     | doubleScore score <= highScore = "51 ~ 100 "
     | otherwise = "score error"
     where doubleScore s = score * 2
           (lowScore, midScore, highScore) = (10, 50, 100)   --通过元祖的模式匹配赋值

where作用域

  1. 函数中的where定义的名字只对本函数可见,不用担心污染其他函数的命名空间。
  2. 函数中多个模式不共享where,where只对定义它的模式可见。
  3. 如果想多个函数或本函数的其他模式匹配中重复使用名字,可以定义到全局。

let

let表达式和where表达式很相似。

let表达式格式: let <bindings> in <expressions>

let 绑定的名字只在in的部分可见。

let和where区别:

letwhere
定义表达式,意味着可以放在代码任意位置关键字,位置固定
作用域作用域小,guard内可见作用域大,函数中所有Guard都可见
语法先绑定值,后使用表达式先使用表达式,后绑定值
可读性声明更近一些,可读性高声明在函数体底部

case 表达式

case表达式格式

case expression of pattern -> result
                   pattern -> result
                   pattern -> result
                   ...

case表达式和函数参数的模式匹配十分的相似,函数参数的模式只能在定义函数时使用,case是表达式, 可以在任何地方使用。

case例子

describeList :: [a] -> String
describeList ls = "The list is " ++ case ls of [] -> "empty."
                                               [x] -> "a singleton list."
                                               xs  -> "a longer list."

函数定义的模式匹配本质上就是case表到式的语法糖,这样写也是等价的:

describeList :: [a] -> String
describeList ls = "The list is " ++ what ls     --调用函数what
    where what [] = "empty."                    --where中定义了函数what的模式匹配
          what [x] = "a singleton list."
          what xs  = "a longer list."          
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值