这是OCaml手册中警告27的描述:
27无关的未使用变量:未使用
letnor 绑定的未使用变量as,并且不以underscore(_)字符开头.
这个警告被打开了jbuilder --dev,我很想知道人们认为它在哪些情况下有用.对我来说,当我编写这样的代码时,获取警告是一件烦恼:
$ utop -w +27 utop # fun (x, y) -> x;; Characters 8-9: Warning 27: unused variable y. - : 'a * 'b -> 'a = <fun>
或者像那样:
utop # let error loc msg = failwith (loc ^ ": " ^ msg);;
val error : string -> string -> 'a = <fun>
utop # let rec eval = function
| `Plus (loc, a, b) -> eval a + eval b
| `Minus (loc, a, b) -> eval a - eval b
| `Star (loc, a, b) -> eval a * eval b
| `Slash (loc, a, b) ->
let denom = eval b in
if denom = 0 then
error loc "division by zero"
else
eval a / denom
| `Int (loc, x) -> x
;;
Characters 33-36:
Warning 27: unused variable loc.
Characters 73-76:
Warning 27: unused variable loc.
Characters 112-115:
Warning 27: unused variable loc.
Characters 287-290:
Warning 27: unused variable loc.
val eval :
([< `Int of 'b * int
| `Minus of 'c * 'a * 'a
| `Plus of 'd * 'a * 'a
| `Slash of 'e * 'a * 'a
| `Star of 'f * 'a * 'a ]
as 'a) ->
int = <fun>
我知道将下划线添加到标识符中就像_loc抑制警告一样,但它与我的观念不相符:
使用下划线,代码变为:
(* Here we have _loc or loc depending on whether it's used. *)
let rec eval = function
| `Plus (_loc, a, b) -> eval a + eval b
| `Minus (_loc, a, b) -> eval a - eval b
| `Star (_loc, a, b) -> eval a * eval b
| `Slash (loc, a, b) ->
let denom = eval b in
if denom = 0 then
error loc "division by zero"
else
eval a / denom
| `Int (_loc, x) -> x
要么
(* Here it can be hard to know what _ stands for. *)
let rec eval = function
| `Plus (_, a, b) -> eval a + eval b
| `Minus (_, a, b) -> eval a - eval b
| `Star (_, a, b) -> eval a * eval b
| `Slash (loc, a, b) ->
let denom = eval b in
if denom = 0 then
error loc "division by zero"
else
eval a / denom
| `Int (_, x) -> x
ivg*_*ivg 10
它在monadic代码中非常有用,而不是常见的语法let绑定,你被迫使用monadic >>=绑定运算符.基本上,在哪里
let x = something in
code
Run Code Online (Sandbox Code Playgroud)
翻译成
something >>= fun x ->
code
Run Code Online (Sandbox Code Playgroud)
如果x未使用,code则仅启用27警告,后者将突出显示,而前者将默认生成警告.启用此警告,为我们揭示了许多错误.例如,它向我们展示了这个代码是错误的:)
用例的另一来源是高阶函数,即map,fold等它捕获的最常见的错误之一:
let bug init =
List.fold ~init ~f:(fun acc xs ->
List.fold ~init ~f:(fun acc x -> x :: acc))
Run Code Online (Sandbox Code Playgroud)
关于丑陋,我完全同意下划线是丑陋的,但在大多数情况下,这是他们的主要目的 - 强调可疑代码.关于您正在展示的示例,在现代OCaml中,可以使用内联记录轻松解决,例如,
type exp =
| Plus of {loc : loc; lhs : exp; rhs: exp}
| ...
Run Code Online (Sandbox Code Playgroud)
因此,您可以省略未使用的字段,而不是使用下划线,
let rec eval = function
| Plus {lhs; rhs} -> eval lhs + eval rhs
Run Code Online (Sandbox Code Playgroud)
您可以在不使用内联记录的情况下使用相同的方法,方法是在程序中节省一些额外的空间并分别定义所有这些记录.在真实世界的例子.