Вопрос по – OCaml Printf.sprintf

11

Почему происходит такое поведение?

# Printf.sprintf ("Foo %d %s") 2 "bar";;
- : string = "Foo 2 bar"

# Printf.sprintf ("Foo %d" ^ " %s") 2 "bar";;
  Printf.sprintf ("Foo %d" ^ " %s") 2 "bar";;
Error: This expression has type string but an expression was expected of type
         ('a -> 'b -> 'c, unit, string) format =
           ('a -> 'b -> 'c, unit, string, string, string, string) format6

Я ожидаю, что сначала будет оценена конкатенация строк, поэтому все будет работать как обычно. Связано ли это с обманом системы типов, который использует Printf?

Ваш Ответ

2   ответа
10

^ оператор. По сути, компилятор OCaml должен знать, что ваша строка формата является литеральной строкой, а литеральная строка должна быть известна во время компиляции. Или же OCaml не может привести вашу строку во время компиляции к этомуBLAHBLAH format6 тип.Printf модуль работает корректно только со строками формата, которые полностью известны во время компиляции, или со строками формата, которые уже приведены кBLAHBLAH format тип.

Как правило, вы можете решить эту проблему с помощью^^ оператор и путем явного приведения всех литеральных строк кBLAHBLAH format типbefore используя эти строки в вашем коде.

Вот еще один пример:

  # Printf.sprintf (if true then "%d" else "%d ") 2;;
  Error: This expression has type string but an expression was expected of type
     ('a -> 'b, unit, string) format =
       ('a -> 'b, unit, string, string, string, string) format6
  (* define a type abbreviation for brevity *)
  # type ('a,'b) fformat = ('a ->'b, unit, string) format;;
  type ('a, 'b) fformat = ('a -> 'b, unit, string) format
  # Printf.sprintf (if true then ("%d":('a,'b)fformat) else ("%d ":('a,'b)fformat)) 2;;
  - : string = "2"

Система OCaml не может распознать, чтоif ... then "a" else "b" может быть приведен кBLAHBLAH format, Если вы бросилиeach literal string себя вBLAHBLAH format, тогда все работает. (Примечание: это не работает, если вы пытаетесь разыгратьif/then/else вBLAHBLAH format, поскольку OCaml не может проверить, что ваша строка является литералом.)

Источником проблемы является требование безопасности типов: OCaml требует наличия аргумента правильного типа для каждого%d а также%s и т.д., и гарантирует это вcompile time, Вы не можете гарантировать безопасность типов сPrintf если не известна вся строка форматаat compile time, Поэтому невозможно использоватьPrintf со строкой формата, вычисленной с помощью сложного алгоритма, например, путем выбора%s а также%d случайно.

Когда мы используемif/then/else чтобы вычислить строку формата, затем OCaml, о, боже, это сложный алгоритм, и безнадежно проверять безопасность типов во время компиляции.^^ Оператор знает оBLAHBLAH format печатает и выдает правильный результат при конкатенации строк формата. Ноif/then/else не знает оBLAHBLAH formatи нет встроенной альтернативыif/then/else (но я полагаю, вы могли бы сами определить такую вещь).

18

это связано с обманом системы типов. Если вы хотите создать строку формата, вам нужно использовать оператор (^^):

# Printf.sprintf ("Foo %d" ^^ " %s") 2 "bar";;
- : string = "Foo 2 bar"

Я не очень хорошо разбираюсь в этой хитрости, но считаю, что компилятор готов продвигать строкуconstant в формат printf, если это требует контекст ввода. Тем не менее, результат("Foo %d" ^ " %s") не является строковой константой, поэтому она не повышается. Оператор (^^) создает контекст ввода, в котором оба операнда могут быть повышены, если они являются строковыми константами.

Вы можете понять, почему это должна быть строковая константа: в противном случае связанные типы (значений, которые должны быть напечатаны) не могут быть определены.

Error: User Rate Limit ExceededPrint.*printfError: User Rate Limit ExceededPervasives.stringError: User Rate Limit ExceededPervasives.format6Error: User Rate Limit ExceededPervasives.string).
Error: User Rate Limit Exceeded... format -> ... format -> ... formatError: User Rate Limit Exceeded
Error: User Rate Limit ExceededprintfError: User Rate Limit Exceeded^Error: User Rate Limit Exceeded^Error: User Rate Limit ExceededprintfError: User Rate Limit Exceeded
Error: User Rate Limit ExceededformatError: User Rate Limit Exceeded

Похожие вопросы