两个相似定义之间的差异

Differences between two similar definitions

有区别吗
(define make-point cons)

(define (make-point x y)
  (cons x y))

?

一种比另一种更有效,还是完全等效?

在语义上它们是等价的:make-pointcons 两个元素。但是第一个是创建 cons 函数的 别名 ,而第二个是定义一个简单调用 cons 的新函数,因此它将是稍微慢一点,但是额外的开销可以忽略不计,如果编译器好的话甚至不存在。

对于cons,你的两个版本没有区别。

对于像 + 这样的可变过程,+(lambda (x y) (+ x y)) 之间的区别在于后者将过程限制为只能使用两个参数调用。

出于好奇,我做了一个快速而肮脏的实验。似乎只是别名 cons 的速度几乎是将其包装在新函数中的两倍。

(define mk-point cons)

(define (make-point x y)
  (cons x y))

(let ((start (current-inexact-milliseconds)))
(let loop ((n 100000000))
      (mk-point 10 10)
      (if (> n 0)
          (loop (- n 1))
          (- (current-inexact-milliseconds) start))))
(let ((start (current-inexact-milliseconds)))
(let loop ((n 100000000))
      (make-point 10 10)
      (if (> n 0)
          (loop (- n 1))
          (- (current-inexact-milliseconds) start))))


;;; Result    
4141.373046875
6241.93212890625
> 

运行 在 Xubuntu 上的 DrRacket 5.3.6 中。

这里有几个不同的问题。

As , one is an indirection, and one is a wrapper. 并指出,如果不进行优化,间接寻址所花费的时间可能是间接寻址的两倍。那是因为别名使得两个变量的 value 成为 same 函数。当系统评估 (cons …)(make-point …) 它评估变量 consmake-point 并返回 same 函数。在间接版本中,make-pointconsnot 相同的函数。 make-point 是一个 new 函数,它再次调用 cons。那是 两次 次函数调用,而不是一次。所以速度 可能 是一个问题,但一个好的优化编译器可能能够使差异忽略不计。

但是,如果您以后能够更改这两个变量中的任何一个的值,那么就会有一个非常的重要区别。当您评估 (define make-point kons) 时,您评估变量 kons once 并设置make-point 的值到您在评估时获得的 one 值。当您评估 (define (make-point x y) (kons x y)) 时,您将 make-point 的值设置为新的功能。每次调用该函数时,都会评估变量 kons,因此会反映对变量 kons 的任何更改。让我们看一个例子:

(define (kons x y)
  (cons x y))

(display (kons 1 2))
;=> (1 . 2)

现在,让我们写一个间接寻址和一个别名:

(define (kons-indirection x y)
  (kons x y))

(define kons-alias kons)

这些现在产生相同的输出:

(display (kons-indirection 1 2))
;=> (1 . 2)

(display (kons-alias 1 2))
;=> (1 . 2)

现在让我们重新定义 kons 函数:

(set! kons (lambda (x y) (cons y x))) ; "backwards" cons

作为 wrapper 围绕 kons 的函数,即间接,看到 的新值kons,但别名没有:

(display (kons-indirection 1 2)) 
;=> (2 . 1)  ; NEW value of kons

(display (kons-alias 1 2))
;=> (1 . 2)  ; OLD value of kons