以下代码运行时没有错误:
let f x y =
print_int (max x y);
print_char ' ';
print_int (x + y) in
for i = 1 to Scanf.scanf "%d" (fun x -> x) do
Scanf.scanf "\n%d %d" f;
print_newline ();
done;
但是当我声明一个变量fmt来保存格式" \ n%d%d"并将其传递给scanf,我收到一个错误,这是新代码:
let f x y =
print_int (max x y);
print_char ' ';
print_int (x + y) in
let fmt = "\n%d %d" in (* added *)
for i = 1 to Scanf.scanf "%d" (fun x -> x) do
Scanf.scanf fmt f; (* edited *)
print_newline ();
done;
我收到此错误:
File "prog.ml", line 7, characters 16-19:
Error: This expression has type string but an expression was expected of type
('a, Scanf.Scanning.in_channel, 'b, 'c -> 'd, 'a -> 'e, 'e) format6
为什么它的工作方式不同?两个代码之间有什么区别吗?
答案 0 :(得分:4)
在OCaml中处理printf / scanf格式使用了一些编译器魔法,它将字符串常量视为适当上下文中的格式。问题是你不再有一个字符串常量。
您可以使用format_of_string
函数将字符串常量预转换为格式。
将您的let fmt =
行更改为:
let fmt = format_of_string "\n%d %d" in
这使您的代码适合我。
答案 1 :(得分:2)
看起来很奇怪,这实际上是一个增值功能:在编译时对扫描函数进行类型检查,为了做到这一点,编译器必须能够在调用时清楚地看到格式字符串网站,并确保没有shenanigans继续使用它。这样的恶作剧可能导致不良行为,如下例所示:
let fmt = "%d" in
let fmt' = fmt ^ (if input_type = "int" then " %d" else " %f") in
(* input_type is defined somewhere else in the program *)
(* the format string could now be either "%d %d" or "%d %f" *)
let a,b = Scanf.scanf fmt' (fun a b -> a,b)
(* the compiler cannot infer a type for `b` *)