Compiler errors OCaml的行产生了神秘的错误
当我执行代码时Compiler errors OCaml的行产生了神秘的错误,compiler-errors,ocaml,Compiler Errors,Ocaml,当我执行代码时 let (a,p) = (2+2, Printf.printf) in p "abc"; p "%d" 3 ;; 我希望看到输出abc3,但得到的是 文件“f.ml”,第1行,字符46-47: 错误:此函数具有类型(单位、输出通道、单位)格式->单位 它适用于太多的论点;也许你忘了一个“;”。 有趣的是,如果我将2+2更改为2,它就会运行 为什么代码会按原样产生错误,但在删除+2后不会产生错误?这是OCaml针对printf的特殊键入技巧和值多态性的组合 您可能知道,Prin
let (a,p) = (2+2, Printf.printf) in p "abc"; p "%d" 3 ;;
我希望看到输出abc3
,但得到的是
文件“f.ml”,第1行,字符46-47:
错误:此函数具有类型(单位、输出通道、单位)格式->单位
它适用于太多的论点;也许你忘了一个“;”。
有趣的是,如果我将2+2
更改为2
,它就会运行
为什么代码会按原样产生错误,但在删除
+2
后不会产生错误?这是OCaml针对printf
的特殊键入技巧和值多态性的组合
您可能知道,Printf.Printf
不接受string
,而是数据类型format
。OCaml类型检查器有一个特殊的规则,用于键入printf
的字符串文本:如果键入为格式
,如果上下文请求:
# "%d";;
- : string = "%d"
# ("%d" : _format);;
- : (int -> 'a, 'b, 'a) format = ...
OCaml类型系统还有另一个技巧,称为值多态性(更准确地说,它是松弛值多态性)。它的目的是正确地键入具有副作用的表达式。我没有解释它的细节,但它限制了多态性:一些称为“expansive”的表达式形式不能有多态类型:
# fun x -> x;;
- : 'a -> 'a = <fun>
# (fun x -> x) (fun x -> x)
- : '_a -> '_a = <fun>
这里,p
具有多态类型('a,out\u channel,unit)格式->'a
<代码>'a可以实例化为多个类型,因此p“abc”;p“%d”3
是可类型化的:多态类型可以在第一次使用p
时实例化为(unit,out\u channel,unit)格式->unit
,第二次使用p
时实例化为(int->unit,out\u channel,unit)格式->int->unit
一旦将常量2
更改为可扩展的2+2
,整个表达式也将扩展,类型也将更改:
# let (a, p) = (2+2, Printf.printf);;
val a : int
val p : ('_a, out_channel, unit) format -> '_a
这里,p
不再具有多态变量'a
,而是单态变量''a
。在第一次使用p
时,此单态变量统一(实例化)为unit
,因此p
的类型变为(单位,输出通道,单位)格式->单位
。它只能使用1个参数,因此第二次使用p
时键入2个参数失败
避免这种情况的一种简单方法是将定义分为两部分:
let a = 2 + 2 in
let p = Printf.printf in
p "abc"; p "%d" 3
我对答案也很感兴趣,这似乎很奇怪。
let a = 2 + 2 in
let p = Printf.printf in
p "abc"; p "%d" 3