之间有什么区别吗?
(define make-point cons)
和
(define (make-point x y)
(cons x y))
一个比另一个更有效,还是完全等同?
答案 0 :(得分:3)
这里有一些不同的问题。
作为Oscar Lopez points out,一个是间接,一个是包装器。 Christophe De Troyer did some timing并注意到没有优化,间接可以花费两倍于间接的时间。这是因为别名使两个变量的值成为相同的函数。当系统评估(cons ...)和(make-point ...)时,它会评估变量缺点和生产点并获取相同的功能。在间接版本中,生产点和缺点是不是相同的功能。 制作点是一个新函数,可以再次调用缺点。那是两个函数调用而不是一个。所以速度可以成为一个问题,但一个好的优化编译器可能会使差异可以忽略不计。
但是,如果您以后能够更改其中任何一个变量的值,那么非常的重要区别。当您评估(定义制作点kons)时,您评估变量 kons 一次并设置 make-point <的值/ strong>到该评估时获得的一个值。当您评估(定义(生成点x y)(kons x y))时,您将生产点的值设置为新函数。每次调用该函数时,都会计算变量 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
围绕 kons 的包装的函数,即间接,看到 kons 的新值,但别名确实如此不:
(display (kons-indirection 1 2))
;=> (2 . 1) ; NEW value of kons
(display (kons-alias 1 2))
;=> (1 . 2) ; OLD value of kons
答案 1 :(得分:2)
从语义上讲,它们相当于:make-point
将cons
两个元素。但第一个是创建cons
函数的别名,而第二个是定义一个简单调用cons
的新函数,因此它会稍微更慢,但额外的开销可以忽略不计,如果编译器是好的,甚至不存在。
答案 2 :(得分:2)
对于cons
,您的两个版本之间没有区别。
对于像+
这样的可变参数程序,+
和(lambda (x y) (+ x y))
之间的区别在于后者限制了仅使用两个参数调用过程。
答案 3 :(得分:2)
出于好奇,我做了一个快速而肮脏的实验。似乎只是别名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中。