Типы печати в Ocaml - PullRequest
       12

Типы печати в Ocaml

0 голосов
/ 24 октября 2019

У меня есть очень простая логика в OCaml:

let load filename =
  let file = get_file filename in
  let len = String.length file in
  Printf.printf "%a\n" file
  ()

(get_file - это функция, которую я написал.) Как вы можете видеть из этого фрагмента, я хочу напечатать содержимое file просто чтобы понять, что он возвращает. Я использовал %a, потому что в одном из учебных пособий по OCaml сказано, что вы должны делать это для такого рода вещей. Когда я говорю «такого рода вещи», я имею в виду канал, и для этого я покажу, как выглядит моя get_file функция:

let get_file filename =
  let channel = open_in_bin filename in
  let length = in_channel_length channel in
  let file = really_input_string channel length in
  close_in channel;
  file

Хорошо, так что ссылаясь на мой код в load метод, я получаю следующую ошибку:

6 |   Printf.printf "%a\n" file
                           ^^^^
Error: This expression has type string but an expression was expected of type
         out_channel -> 'a -> unit

Так что я думаю: «Хорошо, это строка типа - так как это то, что говорится в сообщении - поэтому я должен сделать это в моем printf». Поэтому я изменяю свой printf следующим образом:

Printf.printf "%s\n" file

И все же теперь ошибка:

6 |   Printf.printf "%s\n" file
                    ^^^^^^
Error: This expression has type
         ('a -> 'b, out_channel, unit, unit, unit, 'a -> 'b)
         CamlinternalFormatBasics.fmt
       but an expression was expected of type
         ('a -> 'b, out_channel, unit, unit, unit, unit)
         CamlinternalFormatBasics.fmt
       Type 'a -> 'b is not compatible with type unit 

Я понятия не имею, как вы должны сделать что-то из этого тупого сообщения об ошибке,учитывая сообщение об ошибке, с которого я изначально начинал, когда использовал %a.

Итак, я подумал, что, возможно, file было неправильной попыткой, так как это канал, и, возможно, я что-то упустил. Поэтому вместо этого я пытаюсь распечатать переменную len, которая должна быть просто целым числом. Я изменяю свой printf следующим образом:

Printf.printf "%d\n" len

И получаю еще одно бесполезное (для меня) сообщение об ошибке:

6 |   Printf.printf "%d\n" len
                    ^^^^^^
Error: This expression has type
         ('a -> 'b, out_channel, unit, unit, unit, 'a -> 'b)
         CamlinternalFormatBasics.fmt
       but an expression was expected of type
         ('a -> 'b, out_channel, unit, unit, unit, unit)
         CamlinternalFormatBasics.fmt
       Type 'a -> 'b is not compatible with type unit 

Я попытался переключить printf для len на %a просто чтобы посмотреть, что он сообщил, и я получил это:

6 |   Printf.printf "%a\n" len
                           ^^^
Error: This expression has type int but an expression was expected of type
         out_channel -> 'a -> unit

Да, у него есть тип int. Это то, что я изначально пытался напечатать! Так что это зеркальная ситуация из первых. Одно сообщение об ошибке говорит мне, что переменная имеет определенный тип. Затем я пытаюсь напечатать этот конкретный тип, и получаю более длинное, но гораздо менее полезное (для меня) сообщение об ошибке.

Я не могу найти приличное руководство по OCaml, которое просто проведет вас через этот простой примериспользуя диагностические операторы печати, чтобы определить, что делает язык, поэтому публикуем здесь, чтобы узнать, что я делаю неправильно.

1 Ответ

1 голос
/ 25 октября 2019

Проблема с сообщением об ошибке заключается в том, что семейство функций Printf очень гибкое, что приводит к очень сложному сообщению об ошибке, когда количество аргументов, отправляемых функции, превышает ожидаемое.

В вашемВ первом случае

Printf.printf "%a\n" file ()

Printf получает правильное количество аргументов, поскольку спецификатору %a требуется два аргумента: пользовательский принтер и данные, которые необходимо распечатать. Таким образом, вы получили ошибку типа на file, поскольку file не является функцией печати. ​​

Однако во втором случае

Printf.printf "%s\n" file ()

количество аргументов неверно.

Затем средство проверки типов пытается согласовать ожидаемое количество аргументов с фактическим количеством аргументов. В своем исследовании он приходит к выводу, что с приложением все будет в порядке, если

Printf.printf "%s\n" file

вернул функцию. В частности,

Printf.kprintf (fun _ () -> ()) "%s\n" file

будет в порядке. Это то, что сообщение об ошибке пытается сказать. Если мы сосредоточимся на последнем параметре типа,

Error: This expression has type
         (..., 'a -> 'b) fmt
       but an expression was expected of type
         (..., unit) fmt
       Type 'a -> 'b is not compatible with type unit

Первая строка говорит нам, что количество аргументов по сравнению с аргументами формата потребовало от нас вернуть функцию типа 'a -> 'b в конце печати,Тем не менее, последняя строка сообщает нам, что функция Printf.printf может возвращать только значение типа unit в конце печати. Поскольку unit и 'a -> 'b не одного типа, это ошибка.

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