签名的OCaml功能:
'a -> 'b
可能?
我认为有可能,但是,我不知道答案背后的基本逻辑,所以解释它会很棒:)
编辑:它无法递归循环
答案 0 :(得分:8)
有几个“合法”的答案。一个是永远循环,你排除了:
let rec f x = f x
另一种方法是通过提出异常或终止程序来分歧:
let f x = exit 0
let f x = assert false
let f x = failwith "die"
答案 1 :(得分:0)
可以使用:
let rec x = fun y -> x y;;
我不确定它是如何起作用的。 我知道x会有类型:
`a -> `b
和y会有类型:
`a
所以x:`a->`b y:`a将有类型:
`b
问题在于它似乎进入了一个无限循环。
答案 2 :(得分:0)
有Obj
个模块,具有Obj.magic
功能。您可以使用外部magic
原语来引入%identity
之类的函数,例如:
external magic : 'a -> 'b = "%identity"
但是你必须明白,所有这些绕过了类型系统,应该根本使用。在不破坏类型系统的情况下,类型'a -> 'b
的所有函数共享相同的属性 - 不返回:因此它们应该引发异常(或使用其他非本地退出)或根本不返回。
答案 3 :(得分:-1)
是的!有各种“琐碎”的方法(通过终止程序,抛出异常或永远循环),但这是一个非常重要的方法,直接来自标准库:
external magic: 'a -> 'b = "%identity"
这里,external
用于调用使用OCaml的C API的C函数。通常,字符串将是要调用的C函数的名称,但"%identity"
是一个不生成代码但只返回其参数的编译器内在函数。这利用了OCaml只信任为外部函数提供的类型签名这一事实,因为它无法验证它们。
它是Obj
模块的一部分,其中存在此类低级别操作,并且通常以其完全限定名称Obj.magic
来表示。这是一个不安全的身份证明,如下所示:
OCaml version 4.03.0+dev5-2014-10-15
# external magic: 'a -> 'b = "%identity";;
external magic : 'a -> 'b = "%identity"
# Printf.printf "%d\n" (magic 1);;
1
- : unit = ()
# (* Crash *) print_string (magic 1);;
[1] 4010 segmentation fault (core dumped) ocaml
段错误是因为OCaml在运行时不维护类型信息。此强制转换是未选中 - 编译器/解释器只是接受你的话。最后一个示例尝试取消引用1的内部表示(由于标记位而为0x3)作为指向字符串的指针,以及段错误。
此功能有合法用途,但很少见。一组在Printf
和Scanf
来源,直到采用基于GADT的解决方案。其他用途是在Coq生成的程序中(它具有更强大的类型系统,因此可以证明转换是安全的,即使OCaml不能)。 Obj
模块中的其他函数有时用于修改cons单元以进行尾递归列表操作,以及避免在极其性能关键的代码中出现间接的黑客攻击。
作为非常良好的规则:如果您不完全确定应该使用Obj
模块中的功能,或者不确定此类使用是否安全,不要。使用它们是导致堆损坏的好方法,这很难调试,并且安全漏洞可导致任意代码执行,从类似问题判断在C和C ++中可以被利用。