Functional programming 如何测试两个功能是否相同?

Functional programming 如何测试两个功能是否相同?,functional-programming,scheme,racket,Functional Programming,Scheme,Racket,我在网上找到了一个代码片段: 这让我怀疑这两个函数总是不同的,因为它们有不同的内存位置 但是,如果可以将函数与其他函数进行比较,我如何测试两个函数是否相同?如果它们有不同的变量名呢?例如: (λ(x)(+x1))和(λ(y)(+y1)) 另外,我使用DrRacket来测试代码。你不能。函数被视为不透明值:它们只按标识进行比较,其他什么都没有这是精心设计的。 但是为什么呢?语言不能实现有意义的方法来比较有时可能有用的函数吗?嗯,不是真的,但有时很难理解为什么没有详细阐述。让我们从你的问题中考虑你

我在网上找到了一个代码片段:

这让我怀疑这两个函数总是不同的,因为它们有不同的内存位置

但是,如果可以将函数与其他函数进行比较,我如何测试两个函数是否相同?如果它们有不同的变量名呢?例如:

(λ(x)(+x1))
(λ(y)(+y1))


另外,我使用DrRacket来测试代码。

你不能。函数被视为不透明值:它们只按标识进行比较,其他什么都没有这是精心设计的。


但是为什么呢?语言不能实现有意义的方法来比较有时可能有用的函数吗?嗯,不是真的,但有时很难理解为什么没有详细阐述。让我们从你的问题中考虑你的例子,这两个函数似乎是等价的:

(define ctx0 (lambda (v) `(k ,v)))
(define ctx1 (lambda (v) `(k ,v)))
事实上,他们是。但是,比较这些平等功能能实现什么呢?毕竟,我们同样可以轻松实现另一个功能:

(define ctx2 (lambda (w) `(k ,w)))
无论出于何种目的,该函数都与前两个函数相同,但它将无法通过天真的平等性检查

为了决定两个值是否相等,我们必须定义一些定义相等的算法。考虑到目前为止我提供的示例,这样的算法似乎很明显:两个函数如果(并且仅当)相等,则应将其视为相等。有了这个,我们现在可以有意义地检查两个函数是否相等

……对吗

嗯,噢。这个函数做完全相同的事情,但是它的实现方式不完全相同,所以它没有通过我们的相等性检查。当然,我们可以解决这个问题。准旋转和使用
列表
构造函数基本相同,因此我们可以在大多数情况下将它们定义为等价的

(define ctx4 (lambda (v) (reverse (list v 'k))))
啊!这在操作上也是等价的,但它仍然不能满足我们的等价算法。我们怎样才能做到这一点


事实证明我们不能,真的。函数本质上是抽象单元,我们不需要知道它们是如何实现的,只需要知道它们做什么。这意味着函数相等只能在操作等价性方面得到正确定义;也就是说,实现并不重要,只有行为才重要

这在任何非平凡的语言中都是一个不可判定的问题。不可能确定任何两个函数在操作上是否相等,因为如果我们可以,我们可以解决这个问题

理论上,编程语言可以提供一种尽最大努力确定函数等价性的算法,可能使用α等价性或其他某种度量。不幸的是,依赖函数的实现而不是其行为来确定程序的语义,这实际上是没有用的,因为这违反了函数抽象的基本规律,因此依赖于这样一个系统的任何程序都将是反模式


函数相等是一个很容易解决的问题,当简单的情况看起来很容易时,但是大多数语言都采取了正确的方法,甚至不尝试。这并不是说它不是一个有用的想法:如果可能的话,它将非常有用!但既然不是这样,你就必须使用不同的工具来完成这项工作。

从语义上讲,两个函数
f
g
是相等的,如果它们对每个输入都一致,也就是说,如果对于所有
x
,我们有
(=(fx)(gx))
。当然,对于
x
的每一个可能值,都无法测试这一点

如果您想要做的只是合理地确信
(lambda(x)(+x1))
(lambda(y)(+y1))
是相同的,那么您可以尝试断言这一点

(map (lambda (x) (+ x 1)) [(-5) (-4) (-3) (-2) (-1) 0 1 2 3 4 5])


在您的单元测试中也是如此。

我刚刚尝试了作者在代码中给出的几个示例,“(memq ctx(list ctx0id))”在我测试“(cps”(lambda(x)(if(if(if t)(if x(f a)b)c)ew))时将被评估为true”。但由于memq使用“eq?”来比较两个元素。。。。我很高兴confused@Jackddddd请注意,通过引用lambda表达式,实际上并没有返回lambda,而是返回了符号列表。您链接的代码包括一个小的递归算法,该算法将s表达式(所有表达式都刚刚引用!)转换为它们的CPS等价物。然而,这只是半相关的:代码是通过身份比较函数的,这很好
(让([x(lambda(v)v)])(eq?x))
的计算结果是
#t
,正如人们所期望的那样。我只想补充一点,在引用透明的语言中(即,语言不区分引用和值),函数的引用甚至不相等,因为这样做与语言的语义不兼容。试图断言两个函数在统计公差范围内是相同的有意义吗?也就是说,对于N个
x
,断言
(=(fx)(gx))
,然后计算
f
g
必须具有95%的置信度……@logc许多(可能甚至大多数)函数都有一个无限域,或者至少有一个非常大的域,因此统计方法在计算上是不可行的。
(define ctx3 (lambda (v) (list 'k v)))
(define ctx4 (lambda (v) (reverse (list v 'k))))
(map (lambda (x) (+ x 1)) [(-5) (-4) (-3) (-2) (-1) 0 1 2 3 4 5])
(map (lambda (y) (+ y 1)) [(-5) (-4) (-3) (-2) (-1) 0 1 2 3 4 5])