函数:
fn : 'a -> 'b
现在,是否有任何可以定义并具有此类型的函数?
在标准 ML 中,该函数签名有两种可能的实现方式。一个使用异常,另一个采用递归:
val raises : 'a -> 'b =
fn a => raise Fail "some error";
(* Infinite looping; satisfies the type signature, *)
(* but won't ever produce anything. *)
val rec loops : 'a -> 'b =
fn a => loops a;
第一个解决方案对于定义一个帮助程序函数可能很有用,比如bug
,它可以节省几个击键:
fun bug msg = raise Fail ("BUG: " ^ msg);
另一种解决方案对于定义服务器循环或 REPL 可能很有用。
在 Basis 库中,OS.Process.exit
是这样一个返回未知泛型类型的函数'a
:
- OS.Process.exit;
val it = fn : OS.Process.status -> 'a
具有 val repl = fn : unit -> 'a
型的小型回声 REPL :
fun repl () =
let
val line = TextIO.inputLine TextIO.stdIn
in
case line of
NONE => OS.Process.exit OS.Process.failure
| SOME ":qn" => OS.Process.exit OS.Process.success
| SOME line => (TextIO.print line ; repl ())
end
您可能还会发现有关 Haskell forever
函数的类型签名的这个问题很有用。
我能想到一个例子:
fun f a = raise Div;
我能想到几个:
-
一个递归的,
fun f x = f x
-
任何引发异常的函数,
fun f x = raise SomeExn
-
任何相互递归的函数,例如
fun f x = g x and g x = f x
-
任何使用强制转换的函数(需要特定的编译器支持,下面是莫斯科 ML),
fun f x = Obj.magic x
像这样破坏类型系统可能是作弊,但与具有此类型的所有其他函数不同,此函数实际上返回了一些东西。(在最简单的情况下,它是标识函数。
-
一个函数,如果 Collatz 猜想为假,则无限递归,
fun f x = let fun loop (i : IntInf.int) = if collatz i then loop (i+1) else raise Collatz in loop 1 end
这实际上只是前两者的结合。
-
任何执行任意 I/O 并无限递归的函数,例如
fun f x = (print "Woohoo!"; f x) fun repl x = let val y = read () val z = eval y val _ = print z in repl x end
有人可能会争辩说,异常和无限递归表示相同的理论值⊥(底部)的意思是"没有结果",尽管由于您可以捕获异常而不是无限递归函数,因此您也可以争辩说它们是不同的。
如果您将自己限制为纯函数(例如没有打印或异常)并且仅使用标准 ML(而不是特定于编译器的功能),并且您认为相互递归的情况在功能上是等价的,尽管它们有不同的递归方案,我们又回到了 fun f x = f x
.
fun f x = f x
具有类型'a→'b的原因可能是显而易见的:类型推断算法假设输入类型和输出类型分别是'a和'b,并继续总结函数的唯一约束:f x
的输入类型必须等于f x
的输入类型,并且f x
的输出类型必须等于f x
的输出类型, 在这一点上,类型'A和'B还没有进一步专业化。