您可以将整数与 OCaml 中的范围进行模式匹配吗?

Can you pattern match integers to ranges in OCaml?

作为 Graham 扫描的一部分,我正在编写一个函数来确定线在某个点是向左转还是向右转。考虑到我们有一个函数 determinant point -> point -> point -> int 其中 determinant p0 p1 p2 returns det(p0p1, p0p2),这里是代码:

(* Determines how the line turns at s, when going from t to p*)
let turn t p s =
  let det = det s p t in 
  if det < 0 then
    'r' (* Turning right *)
  else if det > 0 then
    'l'(* Turning left *)
  else 
    's' (* Going straight ahead *)
;;

有没有办法用模式匹配来做到这一点?这是我尝试过的方法,但显然行不通:

let turn t p s =
  match det s p t with
  | < 0 -> 'r'
  | 0 -> 's'
  | > 0 -> 'l'
  
;;

( 请注意,变量/函数名称由 class 确定;虽然我发现单字母名称有点令人困惑,但我可能不会更改它们... )

目前仅 char 支持整数范围(最高 OCaml 5.0)。甚至对于 char 的支持实际上也是部分的:模式 'a'..'d' 只不过是 'a'|'b'|'c'|'d' 的语法糖。但是这种编码只能用于像 char 这样的小整数类型:将区间 0..int_max 分解为 int_max 模式不是 63 位整数的选项。

有可能在模式匹配编译器中支持完整的整数范围(或完全有序的基元类型的范围),但这需要 non-trivial 尚未发生的工作量。

没有

嗯...

模式上的条件守卫可以完成您的建议。

let turn t p s =
  let det = det s p t in 
  if det < 0 then
    'r' (* Turning right *)
  else if det > 0 then
    'l'(* Turning left *)
  else 
    's' (* Going straight ahead *)'

会变成:

let turn t p s =
  match det s p t with
  | n when n < 0 -> 'r'
  | n when n > 0 -> 'l'
  | _            -> 's' 

哪一个更清楚地表达了正在发生的事情是见仁见智的。

那……呢?

要匹配的数据越复杂,争论就越有趣。下面是一个非常人为的示例,具有更好的实际实现。

type num = Int of int | Float of float

let rec cmp a b =
  match a, b with
  | Int a, Int b ->
    if a < b then -1
    else if a > b then 1
    else 0
  | Float a, Float b -> 
    if a < b then -1
    else a > b then 1
    else 0
  | Int a, Float b ->
    let a = float_of_int a in
    if a < b then -1
    else a > b then 1
    else 0
  | Float a, Int b ->
    let b = float_of_int b in
    if a < b then -1
    else a > b then 1
    else 0

使用条件保护:

let rec cmp a b =
  match a, b with
  | Int a, Int b when a < b                -> -1
  | Int a, Int b when a > b                ->  1
  | Int a, Int b                           ->  0
  | Float a, Float b when a < b            -> -1
  | Float a, Float b when a > b            ->  1
  | Float a, Float b                       ->  0
  | Int a, Float b when float_of_int a < b -> -1
  | Int a, Float b when float_of_int a > b ->  1
  | Int a, Float b                         ->  0
  | Float a, Int b when a < float_of_int b -> -1
  | Float a, Int b when a > float_of_int b ->  1
  | _                                      ->  0

仍然是见仁见智,但条件守卫可以帮助“扁平化”pattern-matching 中的嵌套条件。