Почему этот короткий фрагмент OCaml с Printf.printf не работает? - PullRequest
9 голосов
/ 05 марта 2010

Я новичок в OCaml. Я играю с фрагментами типа "привет мир" и столкнулся с этой ситуацией. Вот сеанс с переводчиком с некоторыми дополнительными комментариями:

# let average a b = 
  (a +. b) /. 2.;;
val average : float -> float -> float = <fun>
# average 1. 4.;;
- : float = 2.5
# string_of_float (average 1. 4.);;
- : string = "2.5"

(* this fails...*)
# let _ = Printf.printf (string_of_float (average 1. 4.));;
Error: This expression has type string but an expression was expected of type
         ('a, out_channel, unit) format =
           ('a, out_channel, unit, unit, unit, unit) format6

(* yet this works *)
# "hello!";;
- : string = "hello!"
# let _ = Printf.printf "hello!";;
hello!- : unit = ()

(* another failed attempt *)
# let s = string_of_float (average 1. 4.);;
val s : string = "2.5"
# s;;
- : string = "2.5"
# let _ = Printf.printf s;;
Error: This expression has type string but an expression was expected of type
         ('a, out_channel, unit) format =
           ('a, out_channel, unit, unit, unit, unit) format6

(* and this also works?? *)
# let _ = Printf.printf "2.5";;
2.5- : unit = ()

Итак, вот ситуация. string_of_float (average 1. 4.) возвращает строку, так же, как и "hello!". Когда я даю "hello!" в Printf.printf, это работает как и ожидалось. Когда я даю string_of_float (average 1. 4.) Printf.printf, он терпит неудачу и говорит я ожидал, что не ожидал строку, но этот другой странный тип. Но почему тогда "hello!" и "2.5" работают?

Что происходит?

Ответы [ 2 ]

15 голосов
/ 05 марта 2010

В OCaml есть своего рода «перегрузка» значения строковых литералов. Во время компиляции они могут быть интерпретированы как строка или как формат (которые в системе типов являются совершенно разными) в зависимости от того, что думает средство проверки типов. Если он решает, что это должен быть формат, тогда строка формата анализируется непосредственно во время компиляции (поэтому она может проверять аргументы для printf во время компиляции). (В отличие от C, который анализирует строку во время выполнения.) Однако не существует простого способа преобразования строки в формат во время выполнения. Поэтому, когда вы видите Printf.printf «2.5», «2.5» на самом деле не строка, а особый тип формата, который был проанализирован во время компиляции. Вот почему вы не можете заменить его на строку.

В несвязанной заметке, если вы просто хотите напечатать строку, вы можете использовать print_string (или print_endline, если вы хотите новую строку).

3 голосов
/ 05 марта 2010
Printf.printf "%s" anyStringExpr

будет работать. Первый аргумент к printf несколько магический. (Другие будут заполнять детали.)

...