用 let 重建 OCaml 模式
Posted
技术标签:
【中文标题】用 let 重建 OCaml 模式【英文标题】:OCaml pattern reconstruction with let 【发布时间】:2014-05-27 03:31:58 【问题描述】:所以我注意到可以用“let”表达式重构任何模式,即使它是一个函数声明。
它在以下情况下非常有用:
let [c; f; x] = map (fun _ -> scanf " %f" id) (1--3) in ...
但是,这会发出警告,因为该模式并不详尽:确实,它可能会失败。但在我的情况下,这正是模式不匹配时的预期行为(并且我对输入的断言是错误的):语句应该失败(并且失败可能会在堆栈中的某个点被捕获)。
我不喜欢这些警告(而且我不想全局关闭它们!)所以我不得不依靠非常繁琐(而且不安全):
let c, f, x = match (map (fun _ -> scanf " %f" id) (1--3)) with
| [c; f; x] -> c, f, x
| _ -> failwith "wrong assertion"
in ...
有没有办法获得第一个替代方案的简洁语法而没有可怕的警告?或者另一种结构比完整的匹配语句涉及更少的输入?
注意:我认为如果能够指定一个函数只采用 sum 类型的给定替代项,而不在声明站点发出警告,那也很好。调用者需要确保他使用正确的参数,否则他会收到警告......
type ast = Id of string | Var of string * int
let foo (Var(s,n)) = ...
foo (Var("bar", 42)) (* ok *)
foo (Id "bar") (* warning; or even error *)
(这是因为对我来说,像“foo s n”这样的签名并不能清楚地表明 foo 旨在与 Var-constructed ast 的数据一起使用。)
【问题讨论】:
你可以定义let foo (s, n) = ...
,如果可能的话,由调用者从ast
获取(s, n)
。
是的,但这并不能解决问题。例如,如果另一个替代(甚至类型)具有相同的签名怎么办?
您可能希望有选择地关闭警告,而不是任何类型的类型级别保证。最好的办法是编写一个语法扩展,将let
派生形式转换为与failwith
分支匹配的模式。
谢谢,这听起来更像是我想要实现的目标。
【参考方案1】:
您可以使用变体类型:
type ast = [`Id of string | `Var of string * int]
let foo (`Var (s, n)) = (s, n)
(* val foo : [< `Var of 'a * 'b ] -> 'a * 'b *)
foo (`Var("bar", 42)) (* : string * int = ("bar", 42) *)
foo (`Id "bar") (* Error: This expression has type [> `Id of string ] *)
【讨论】:
是的,但很遗憾不能调用 foo,因为您使用带有 sum 类型对象的变体来定义它:/ @LP_ 你要问的是真的不可能,没有依赖类型。你能得到的最接近的是使用变体类型——但是 OCaml 类型系统限制了你可以使用它们的程度。Var ("foo", 42)
的类型确实是ast
,OCaml 类型检查器中没有静态分析敢质疑它。以上是关于用 let 重建 OCaml 模式的主要内容,如果未能解决你的问题,请参考以下文章