Когда полезно предупреждение OCaml 27 «Безвредная неиспользуемая переменная»? - PullRequest
0 голосов
/ 22 мая 2018

Это описание предупреждения 27 из руководства OCaml :

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 подавляет предупреждения, но это не совместимо с моими представлениями о том, что:

  1. переменные, начинающиеся с подчеркивания, некрасивы и предназначены для использования в сгенерированном коде, скрытом от программиста;
  2. имя, данное чему-либо, не должно изменяться в зависимости от того, как оно используется (включая неиспользуемое).

Используя подчеркивания, код становится:

(* 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

Ответы [ 2 ]

0 голосов
/ 31 мая 2018

Для меня это предупреждение полезно для того, чтобы напомнить мне, чтобы я более подробно изложил свое намерение.Если мы возьмем ваш пример:

fun (x, y) -> x;;

Ваше намерение состоит в том, чтобы использовать только первый элемент.Если мы переписываем это так:

fun (x, _ ) -> x;;

Вы используете сопоставление с образцом в параметре, чтобы сделать ваш код более кратким, но объясняете свое намерение использовать только первый элемент.Добавленная стоимость в этом примере мала, что связано с очень простой реализацией.Но в реальных функциях это предупреждение способствует хорошей привычке кодирования.

0 голосов
/ 22 мая 2018

Это очень полезно в монадическом коде, где вместо общих синтаксических привязок let вы вынуждены использовать монадический оператор связывания >>=.В основном, где

let x = something in
code

переводится в

something >>= fun x ->
code

Если x не используется в code, то только с включенным предупреждением 27 будет выделено последнее, тогда как первоевыдаст предупреждение по умолчанию.Включение этого предупреждения выявило много ошибок для нас.Например, он показал нам, что этот код содержит ошибки:)

Другим источником случаев использования являются функции более высокого порядка, т. Е. 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

Вы можете использовать тот же подход без использования встроенных записей, сэкономив некоторое дополнительное пространство в вашей программе и определив все эти записи отдельно.Пример реального мира .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...