您可以将整数与 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 中的嵌套条件。
作为 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 中的嵌套条件。