Chapter3 - Pattern Match

模式匹配 (Pattern Matching)

 

模式匹配允许你通过一些定义的标识符的值来执行不同的算法步骤,他有点像之前的

if ... then ... else,也可能跟类似 C++ 跟 C# 的 switch,但更加强大。

 

下面我们来看一个例子:

 


# light

let   rec  luc x =
    
match  x  with
    
|  x  when  x <=  0   ->  failwith  " value must be greater than 0 "
    
|   1   ->   1
    
|   2   ->   3
    
|  x  ->  luc (x -  1 ) + luc(--x -  2 )


 

printfn "(luc 2) = %i" (luc 2)

printfn "(luc 6) = %i" (luc 6)

 

结果为

(luc 2) = 3

(luc 6) = 18

 

首先我们来介绍以下luc,他跟之前将的斐波拉契数列很像,唯一不同的只有起始值。

like 1,3,4,7,11,18,29....

然后是解释,我们传递了一个参数 x ,然后match x with 表示我们要将 x 与以下的集中模式进行匹配,

各个模式间用 | 进行分割。

如第一次使用2为参数进行调用,因为他会直接匹配到2,所以最后的结果是3.

第二次,我们使用6,什么都不会匹配到,所以他到了 x -> 这里,这里表示任意的x都会匹配到。

当然,前面的第一个匹配模式已经决定了 x 是大于 0 的数。

在第一个模式里,你可以看到有一个限制,这里称之为护卫(Guard),用 when 来限制,

当 x 小于等于 0 的时候,他会匹配到第一个模式,然后抛出异常。

 

下面的另外一个例子则表示了,我们可以讲模式的匹配写到一行了,而 _ 则表示匹配任意的值。

 


# light

let  booleanToString x =
    
match  x  with   false   ->   " False "   |  _  ->   " True "


下面是另一种比较有用的用法,你可以用 | 来连接两个不同的模式,让他们返回相同的东西。

 


# light

let  stringToBoolean x =
    
match  x  with
    
|   " True "   |   " true "   ->   true
    
|   " False "   |   " false "   ->   false
    
|  _  ->  failwith  " unexpected input "

 
printfn  " (booleanToString \ " true \ " ) = %b "  (stringToBoolean  " true " )
printfn  " (bolleanToString \ " Hello\ " ) = %b "  (stringToBoolean  " Hello " )


 

结果:

(booleanToString "true") = true

 

第二个因为前面的都匹配不到,所以由最后一个 _ 匹配到并抛出异常。

接下来的一个 “或” 跟 “与”的例子则展示了如何同时匹配多个值。

 


# light

let  myOr b1 b2 =
    
match  b1,b2  with
    
|   true , _  ->   true
    
|  _,  true   ->   true
    
|  _  ->   false

 
let  myAnd p =
    
match  p  with
    
|   true true   ->   true
    
|  _  ->   false


 

或即是当传递的两个条件,只要有一个为真,结果就为真,否则为假。

与即是只有当传递的两个条件都为真是,结果才为真。这里有一个有趣的地方,也就是 “与”的那里,

编译器在这里能够自动的推断出 p 为一个元组,并把它拆开来进行模式匹配。

 

另外一个用法,也是比较推荐的用法,就是用模式匹配来处理列表(list)。

 


let  listOfList = [[ 1 , 2 , 3 ], [ 4 , 5 , 6 ], [ 7 , 8 ]]

let   rec  concatList l =
    
match  l  with
    
|  head :: tail  ->  head @ (concatList tail)
    
|  []  ->  []

let   rec  concatListOrg l =
    
if  List.nonempty l  then
        
let  head = List.hd l  in
        
let  tail = List.tl l  in
        head @ (concatListOrg tail)
    
else
        []


 

上面的两个函数的效果是一样的,但我们能发现,使用模式匹配的话,代码会显得简介很多。

这是得益于模式匹配推断出 l 是一个列表,他能够自动的帮我们把列表进行分割,head代表列表的第一个元素,

tail 则表示余下的元素,当传入的列表能够进行分割的时候,就把第一个元素拿出来,然后递归的调用函数,

并将第一个元素跟函数下一次调用的结果进行链接。

 

let primes = concatList listOfList

 

结果:

[1,2,3,4,5,6,7,8]

 

模式匹配还能够对列表进行复杂的匹配,我们来看下一个例子。

 


let   rec  findSequence l =
    
match  l  with
    
|  [x; y; z]  ->
        printfn  " Last 3 member in the list were %i %i %i "
        x y z
    
|   1  ::  2  ::  3  :: tail  ->
        printfn  " Found sequence 1,2,3 within the list "
        findSequence tail
    
|  head :: tail  ->  findSequence tail
    
|  []  ->  ()

 


我们先来看结果再解释。

 

let testSequence = [1; 2; 3; 4; 5; 6; 3; 2; 1]

findSequence testSequence

-----------------------

Found sequence 1,2,3 within the list

Last 3 numbers in the list were 3 2 1

-----------------------

 

首先解释第一个模式:当匹配的列表只有3个元素的时候匹配。并把剩余的3个元素按顺序赋予 x y z,

第二个模式 : 当列表以 1 2 3 开头的时候匹配,并将剩余的元素作为参数再次调用findSequence

第三个模式 :分割列表为第一个头元素与剩余元素,并将剩余的元素作为参数再次调用findSequence

最后一个 : 当列表为空,则结束。

当第一次传递testSequence进去的时候,匹配到了第二个模式,因为testSequence是以1 2 3 开头的列表

然后把剩下的元素继续作为参数调用函数,则相当于 findSequence [4;5;6;3;2;1]

这次调用会匹配到第三个模式,他将列表拆分后再次调用,直到列表只剩下3个元素,

则匹配到第一个模式,输出最后的三个元素。

 

最后一个例子是可以使用 function 关键字来取消在定义函数时需要的参数定义:

 


let   rec  conactStringList =
    
function  head :: tail  ->  head + conactStringList tail
            
|  []  ->   ""


转载于:https://www.cnblogs.com/SinSay/archive/2010/09/20/1831455.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值