Ocaml:使用布尔运算符进行模式匹配

时间:2014-09-14 20:35:02

标签: boolean pattern-matching ocaml

我正在尝试编写一个函数“dom_rank r1 r2”,根据两张扑克牌的相对等级返回一个布尔值(等级是我定义的类型,它有值“Six”,“Seven”,“Eight” “.....”King“,”Ace“)。如果r1是King而r2是Jack,则r1大于r2并且函数返回true,如果r1是Six而r2是Ten,则函数返回false。据我所知,我可以列出两种卡输入的所有可能性(我只处理六A牌,这有三种不同的可能性)但我正在尝试编写更简单的代码。该方法类似于:

let dom_rank r1 r2 = match r1, r2 with
  | Ace, _ -> true
  | King, (Queen || Jack || Ten ........) -> true

我在布尔表达式“(Queen || Jack || Ten ........)”的开头遇到语法错误。为什么我不能以这种方式列出r2的几种可能性?有没有办法在Ocaml中编写这个表达式?

2 个答案:

答案 0 :(得分:5)

“||” operator是一个布尔运算符,你必须用简单的“|”分隔模式,如下所示:

| King, (Queen | Jack | Ten | ... ) -> true

但是,使用这种方法,你仍然会在很长一段时间内写下“六”这个词。 一个好的方法是巧妙地使用通配符:

match r1, r2 with
| Ace, _ -> true
| _, Ace -> false (* at this point, neither card is an ace *)
| King, _ -> true
| _, King -> false
| Queen, _ -> true
| (* and so on *)

这样,每个卡片排名只有两个模式,并且没有键入两次以上的卡片名称(非卡片名称可以复制粘贴)

不太安全但方便的方法是检查您的类型定义是否正确顺序:

type rank = Six | Seven | Eight | ... | Ace
let () = assert ( Six < Eight )

根据这个定义,相对于标准比较运算符,卡应该处于良好的顺序(参见模块Pervasives)。确保进行一些测试,因为对该类型的任何修改都可能会破坏您的订单。

答案 1 :(得分:1)

正如你自己所说,||是一个布尔运算符。 QueenJack等不是布尔值。因此,您不能对它们应用布尔运算符(更不用说您不能将任意表达式用作match中的模式)。

您可以做的是将每个旁边的多个模式分隔为|,如下所示:

| King, Queen | King, Jack| King, Ten |... -> true

当然,这并不像你需要每次拼出King一样简洁。您可以通过使用嵌套模式匹配而不是在元组上匹配来避免它们:

let dom_rank r1 r2 =
  match r1 with
  | Ace  -> true
  | King-> 
    (match r2 with
     | Ace -> false
     | _ -> true)
  | ...
  | Seven ->
    (match r2 with
     | Six, Five, Four, Three, Two -> true
     | _ -> false)

另一种方法是定义一个函数,将每个等级映射到一个整数,然后将dom_rank定义为:

let dom_rank r1 r2 = int_of_rank r1 >= int_of_rank r2

这应该减少了很多重复,在我看来是最好的版本。