这是OCaml manual:
中警告27的说明27无害的未使用变量:未与
let
或as
绑定的未使用变量,并且不以下划线(_
)字符开头。
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
答案 0 :(得分:10)
它在monadic代码中非常有用,而不是常见的语法let
绑定,你被迫使用monadic >>=
绑定运算符。基本上,在哪里
let x = something in
code
转换为
something >>= fun x ->
code
如果x
中未使用code
,则仅启用27警告,后者将突出显示,而前者将默认生成警告。启用此警告,为我们揭示了许多错误。例如,它向我们显示this code是错误的:)
另一个用例来源是高阶函数,即map
,fold
等。它捕获了一个最常见的错误:
let bug init =
List.fold ~init ~f:(fun acc xs ->
List.fold ~init ~f:(fun acc x -> x :: acc))
关于丑陋,我完全同意下划线是丑陋的,但在大多数情况下,这是他们的主要目的 - 强调可疑代码。关于您在现代OCaml中显示的示例,可以使用内联记录轻松解决,例如,
type exp =
| Plus of {loc : loc; lhs : exp; rhs: exp}
| ...
因此,您可以省略未使用的字段
,而不是使用下划线 let rec eval = function
| Plus {lhs; rhs} -> eval lhs + eval rhs
您可以在不使用内联记录的情况下使用相同的方法,方法是在程序中节省一些额外空间并分别定义所有这些记录。 real-world示例。
答案 1 :(得分:1)
对我来说,这个警告很有用,以提醒我更明确的意图。如果我们举个例子:
fun (x, y) -> x;;
您的意图是仅使用第一个元素。如果我们用这种方式重写它:
fun (x, _ ) -> x;;
您在参数中使用模式匹配以使代码更简洁,但您解释了仅使用第一个元素的意图。此示例中的附加值很小,与非常简单的实现有关。但在现实生活中,这种警告促进了编码的良好习惯。