fee*_*sum 6 ocaml compiler-errors
当我执行代码
let (a,p) = (2+2, Printf.printf) in p "abc"; p "%d" 3 ;;
Run Code Online (Sandbox Code Playgroud)
我希望看到输出abc3,但相反
File "f.ml", line 1, characters 46-47:
Error: This function has type (unit, out_channel, unit) format -> unit
It is applied to too many arguments; maybe you forgot a `;'.
Run Code Online (Sandbox Code Playgroud)
有趣的是,如果我换2+2到2,它会运行.
为什么代码会产生错误,但不会+2删除?
OCaml的特殊输入技巧printf和价值多态的组合.
您可能知道,Printf.printf不采用string数据类型format.OCaml类型检查器有一个特殊的规则,用于键入字符串文字printf:如果键入的内容就像format上下文请求一样:
# "%d";;
- : string = "%d"
# ("%d" : _format);;
- : (int -> 'a, 'b, 'a) format = ...
Run Code Online (Sandbox Code Playgroud)
OCaml类型系统还有一个叫做值多态的技巧(更确切地说,它是宽松的值多态).其目的是正确键入具有副作用的表达式.我没有解释它的细节,但它限制了多态性:某些形式的表达式称为"扩展"不能具有多态类型:
# fun x -> x;;
- : 'a -> 'a = <fun>
# (fun x -> x) (fun x -> x)
- : '_a -> '_a = <fun>
Run Code Online (Sandbox Code Playgroud)
在上面,(fun x -> x) (fun x -> x)没有多态类型,而身份函数fun x -> x有.这是由于表达形式(fun x -> x) (fun x -> x):它是"膨胀的".奇怪的类型变量'_a是单态类型变量:它只能被实例化为某种类型.另一方面,'a对于每次使用vlaue,可以将多态变量实例化为不同的类型.
我们回到你的代码:
# let (a, p) = (2, Printf.printf);;
val a : int
val p : ('a, out_channel, unit) format -> 'a
Run Code Online (Sandbox Code Playgroud)
这里,p有一个多态类型('a, out_channel, unit) format -> 'a.'a可以实例化为多个类型因此p "abc"; p "%d" 3是典型的:多态类型可以实例化为(unit, out_channel, unit) format -> unit第一次使用p,并且(int -> unit, out_channel, unit) format -> int -> unit第二次使用p.
一旦你改变常数2来2+2,这是广阔的,整个表达式变得膨胀也和打字的变化:
# let (a, p) = (2+2, Printf.printf);;
val a : int
val p : ('_a, out_channel, unit) format -> '_a
Run Code Online (Sandbox Code Playgroud)
在这里,p不再是多态变量'a而是单态变量'_a.这个单形变量unit在第一次使用时被统一(实例化),p结果p变成了类型(unit, out_channel, unit) format -> unit.它只需要1个参数,因此第二次使用p带2个参数的输入失败.
避免这种情况的一种简单方法是将您的定义分为两部分:
let a = 2 + 2 in
let p = Printf.printf in
p "abc"; p "%d" 3
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
177 次 |
| 最近记录: |