compiler-errors - OCaml 行产生神秘错误

标签 compiler-errors ocaml

当我执行代码时

let (a,p) = (2+2, Printf.printf) in p "abc"; p "%d" 3 ;;

我希望看到输出 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 `;'.

有趣的是,如果我改变 2+22 ,它运行。

为什么代码会按原样产生错误,但不会产生 +2删除?

最佳答案

OCaml 的特殊打字技巧的组合 printf和值多态性。

您可能知道,Printf.printf不带string但数据类型 format . OCaml 类型检查器有一个特殊的规则来输入 printf 的字符串文字。 : 如果输入为 format如果上下文要求:

# "%d";;
- : string = "%d"
# ("%d" : _format);;
- : (int -> 'a, 'b, 'a) format = ...

OCaml 类型系统还有一个技巧叫做值多态性(更准确地说,它是松弛值多态性)。其目的是正确键入带有副作用的表达式。我不解释它的细节,但它限制了多态性:某些称为“扩展”的表达式不能具有多态类型:
# fun x -> x;;
- : 'a -> 'a = <fun>
# (fun x -> x) (fun x -> x)
- : '_a -> '_a = <fun>

在上面,(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

在这里,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的第二次使用.

一旦你改变了常量 22+2 ,这是膨胀的,整个表达式也变得膨胀,并且类型改变:
# let (a, p) = (2+2, Printf.printf);;
val a : int
val p : ('_a, out_channel, unit) format -> '_a

在这里,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

关于compiler-errors - OCaml 行产生神秘错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32839002/

相关文章:

testing - 如何定义导出单个函数的模块?

Ocaml:导出 mli 文件中的类型

ocaml - OPAM : External solver failure 问题

java - BuildTools.jar Minecraft 服务器安装无法正常工作

c++ - Node 插件编译错误

eclipse - Eclipse AJDT-Java方面类上的错误消息 “This method must return a result of type int”

ocaml - 多个工作进程的 ocp-build.conf 语法?

android - 错误 :(3, 5) 找不到与给定名称匹配的资源

scala - 为什么没有找到琐碎的隐式?

ocaml - 为什么我无法访问我的 ocsigen 网站?