将其参数应用于自身的函数?
考虑以下 SML 函数:
fn x => x x
这会产生以下错误(新泽西州标准 ML v110.72):
stdIn:1.9-1.12 Error: operator is not a function [circularity]
operator: 'Z
in expression:
x x
我可以理解为什么不允许这样做 - 首先,我不太确定如何写下它的内容类型将是——但这并不是完全无意义的;例如,我可以将身份函数传递给它并取回它。
这个函数有名字吗? (有没有办法用SML来表达?)
Consider the following SML function:
fn x => x x
This produces the following error (Standard ML of New Jersey v110.72):
stdIn:1.9-1.12 Error: operator is not a function [circularity]
operator: 'Z
in expression:
x x
I can sort of see why this isn't allowed -- for one, I'm not really sure how to write down what its type would be -- but it's not completely nonsensical; for instance, I could pass the identity function to it and get it back.
Is there a name for this function? (Is there a way to express it in SML?)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
无法用具有类似 ML 类型系统的语言来表达此功能。即使使用恒等函数,它也不起作用,因为
x
中的第一个x
和第二个x x
必须是该函数的不同实例,类型为( _a->_a)->; (_a -> _a)
和_a -> _a
,分别针对某些类型_a
。事实上,类型系统被设计为禁止像
无类型 lambda 演算那样的构造。在动态类型语言Scheme中,可以编写这样的函数:
并得到预期的结果
There is no way to express this function in a language with an ML-like type system. Even with the identity function it wouldn't work, because the first
x
and the second inx x
would have to be different instances of that function, of type(_a -> _a) -> (_a -> _a)
and_a -> _a
, respectively, for some type_a
.In fact, type systems are designed to forbid constructs like
in the untyped lambda calculus. In the dynamically typed language Scheme, you can write this function:
and get the expected result
像这样的函数经常在定点组合器中遇到。例如,Y 组合器的一种形式写作
λf.(λx. f (xx)) (λx.f (xx))
。定点组合器用于在无类型 lambda 演算中实现一般递归,而无需任何额外的递归构造,这也是使无类型 lambda 演算图灵完备的一部分。当人们开发简单类型 lambda 演算时,这是一个基于 lambda 演算的朴素静态类型系统,他们发现不再可能编写这样的函数。事实上,在简单类型的 lambda 演算中不可能执行一般的递归;因此,简单类型的 lambda 演算不再是图灵完备的。 (一个有趣的副作用是,简单类型 lambda 演算中的程序总是终止。)
真正的静态类型编程语言(如标准 ML)需要内置递归机制来克服该问题,例如命名递归函数(用
val rec
或fun
定义)和命名递归数据类型。仍然可以使用递归数据类型来模拟您想要的东西,但它并不那么漂亮。
基本上,您想要定义一个类似
'a foo = 'a foo ->; 的类型。 'a
;然而,这是不允许的。相反,您可以将其包装在数据类型中:datatype 'a foo = Wrap of ('a foo -> 'a);
基本上,
Wrap
和unwrap
code> 用于在'a foo
和'a foo ->; 之间进行转换。 'a
,反之亦然。每当您需要调用函数本身时,您必须显式编写
(unwrap x) x
(或unwrap x x
),而不是x x
;即unwrap
将其转换为一个函数,然后您可以将其应用于原始值。PS 另一种 ML 语言 OCaml 有一个启用递归类型的选项(通常禁用);如果您使用
-rectypes
标志运行解释器或编译器,则可以编写类似fun x ->; 的内容。 x x 。基本上,在幕后,类型检查器会找出需要“包装”和“展开”递归类型的位置,然后为您插入它们。我不知道有任何标准 ML 实现具有类似的递归类型功能。
Functions like this are often encountered in fixed-point combinators. e.g. one form of the Y combinator is written
λf.(λx.f (x x)) (λx.f (x x))
. Fixed-point combinators are used to implement general recursion in untyped lambda calculus without any additional recursive constructs, and this is part of what makes untyped lambda calculus Turing-complete.When people developed simply-typed lambda calculus, which is a naive static type system on top of lambda calculus, they discovered that it was no longer possible to write such functions. In fact, it is not possible to perform general recursion in simply-typed lambda calculus; and thus, simply-typed lambda calculus is no longer Turing-complete. (One interesting side effect is that programs in simply-typed lambda calculus always terminate.)
Real statically-typed programming languages like Standard ML need built-in recursive mechanisms to overcome the problem, such as named recursive functions (defined with
val rec
orfun
) and named recursive datatypes.It is still possible to use recursive datatypes to simulate something like what you want, but it is not as pretty.
Basically, you want to define a type like
'a foo = 'a foo -> 'a
; however, this is not allowed. You instead wrap it in a datatype:datatype 'a foo = Wrap of ('a foo -> 'a);
Basically,
Wrap
andunwrap
are used to transform between'a foo
and'a foo -> 'a
, and vice versa.Whenever you need to call a function on itself, instead of
x x
, you have to explicitly write(unwrap x) x
(orunwrap x x
); i.e.unwrap
turns it into a function that you can then apply to the original value.P.S. Another ML language, OCaml, has an option to enable recursive types (normally disabled); if you run the interpreter or compiler with the
-rectypes
flag, then it is possible to write things likefun x -> x x
. Basically, behind the scenes, the type-checker figures out the places where you need to "wrap" and "unwrap" the recursive type, and then inserts them for you. I am not aware of any Standard ML implementation that has similar recursive types functionality.