【问题标题】:Function which applies its argument to itself?将其参数应用于自身的函数?
【发布时间】:2012-02-28 01:38:32
【问题描述】:

考虑以下 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来表达?)

【问题讨论】:

  • 如果有人感兴趣,我发现这叫U Combinator (see bottom of page),但找不到更多相关信息。
  • 我不知道它被称为 U 组合子,但正如该页面所述,它用于构建我在答案中输入的无类型 lambda 演算的(显然最短的)非终止程序.

标签: types functional-programming sml smlnj


【解决方案1】:

没有办法用类似 ML 的类型系统的语言来表达这个功能。即使使用标识函数,它也不起作用,因为 x x 中的第一个 x 和第二个 x x 必须是该函数的不同实例,分别为 (_a -> _a) -> (_a -> _a)_a -> _a 类型,对于某些类型 @ 987654325@.

事实上,类型系统的设计目的是禁止像

(λx . x x) (λx . x x)

在无类型的 lambda 演算中。在动态类型语言Scheme中,可以写这个函数:

(define (apply-to-self x) (x x))

得到预期的结果

> (define (id x) x)
> (eq? (apply-to-self id) id)
#t

【讨论】:

  • “因为 x x 中的第一个 x 和第二个 x 必须是该函数的不同实例”:出于好奇,具有惰性求值的语言呢?除此之外,我不确定 SML 中是否有类似“实例”的东西(除了有副作用的地方)。这个问题只是一个打字问题(没有类型,通常没有意义,但并非总是如此)。
  • @Hibou57 例如,我的意思是泛型函数的不同具体类型的实例化。
【解决方案2】:

这样的函数经常在定点组合器中遇到。例如Y combinator 的一种形式写成λf.(λx.f (x x)) (λx.f (x x))。定点组合器用于在无类型 lambda 演算中实现一般递归,无需任何额外的递归构造,这也是无类型 lambda 演算图灵完备的部分原因。

当人们开发simply-typed lambda calculus,这是一个基于 lambda 演算的简单静态类型系统时,他们发现不再可能编写这样的函数。事实上,在简单类型的 lambda 演算中执行一般递归是不可能的。因此,简单类型的 lambda 演算不再是图灵完备的。 (一个有趣的副作用是简单类型的 lambda 演算中的程序总是终止。)

真正的静态类型编程语言(如标准 ML)需要内置递归机制来解决该问题,例如命名递归函数(使用 val recfun 定义)和命名递归数据类型。

仍然可以使用递归数据类型来模拟你想要的东西,但它不是那么漂亮。

基本上,你想定义一个像'a foo = 'a foo -> 'a这样的类型;但是,这是不允许的。而是将其包装在数据类型中:datatype 'a foo = Wrap of ('a foo -> 'a);

datatype 'a foo = Wrap of ('a foo -> 'a);
fun unwrap (Wrap x) = x;

基本上,Wrapunwrap 用于在'a foo'a foo -> 'a 之间进行转换,反之亦然。

当你需要调用一个函数本身,而不是x x,你必须显式写(unwrap x) x(或unwrap x x);即unwrap 将其转换为一个函数,然后您可以将其应用于原始值。

附:另一种 ML 语言 OCaml 具有启用递归类型的选项(通常禁用);如果您使用-rectypes 标志运行解释器或编译器,则可以编写fun x -> x x 之类的东西。基本上,在幕后,类型检查器会找出您需要“包装”和“解包”递归类型的位置,然后为您插入它们。我不知道任何具有类似递归类型功能的标准 ML 实现。

【讨论】:

  • “我不知道有任何标准 ML 实现具有类似的递归类型功能”:SML 的定义不允许这样做,因此任何实现都不会有这个。将它包装在数据类型中的需要可能是有道理的。看着像'a f = 'a f -> 'a 这样的类型定义让我觉得这是一个重写规则或评估,而不是一个类型。但可能是我对此有偏见。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-07
  • 2022-07-08
  • 2013-10-05
  • 2013-12-14
  • 2023-04-05
  • 1970-01-01
相关资源
最近更新 更多