Scheme 中的 Y 组合器,使用惰性求值?
Y-combinator in Scheme, using lazy evaluation?
有谁知道如何在 Scheme 中实现 Y 组合器,特别是惰性求值和附加参数?我的理解是 Scheme (promise?) (delay) 和 (force) 提供惰性求值支持。
据我了解,Y-combinator with application 如下所示,但由于默认情况下应用顺序评估,因此无法在 Scheme 中使用。
((lambda (f)
((lambda (x) (f (x x)))
(lambda (x) (f (x x)))))
(lambda (r) (r)))
这是一个建议的解决方案(Z 组合器),但是它使用另一个带参数的 lambda 函数作为解决方案:
;; Z-combinator
(define Z
(lambda (f)
((lambda (g) (f (g g)))
(lambda (g) (f (lambda args (apply (g g)
args)))))))
;Value: z
((Z (lambda (r)
(lambda (x)
(if (< x 2)
1
(* x (r (- x 1))))))) 5)
;Value: 120
;; end Z-combinator
根据解决方案更新
Y-combinator如下:
;; Y-combinator
(define Y
(lambda (f)
((lambda (x) (f (delay (x x))))
(lambda (x) (f (delay (x x)))))))
;Value: y
;; end Y-combinator
;; Non tail recursive
((Y (lambda (r)
(lambda (x)
(if (< x 2)
1
(* x ((force r) (- x 1)))))))
5)
;Value: 120
;; Tail - recursive
((Y (lambda (r)
(lambda (x acc)
(if (< x 2)
acc
((force r) (- x 1) (* x acc))))))
5 1)
;Value: 120
感谢您的指导!
是的,经过严格评估,自我应用程序 (x x) 会导致出现无限循环。如果你延迟这个,你可以使用 y 组合器,只要你也 'force' 在它的使用站点延迟对象:
(define (test)
(((lambda (f)
((lambda (x) (f (delay (x x))))
(lambda (x) (f (delay (x x))))))
(lambda (r)
(lambda (x)
(if (< x 2)
1
(* x ((force r) (- x 1)))))))
5))
制作在严格设置下工作的 y 组合器变体的正常方法是 eta 扩展自应用程序,这是另一种延迟它但不需要明确应用力的方法。相反,强制是由函数应用程序完成的。
普通顺序Y组合器,这里在Lazy Racket中计算(ack 3 6)
:
#lang lazy
(define Y
(lambda (f)
((lambda (g) (g g))
(lambda (g) (f (g g))))))
((Y (lambda (ackermann)
(lambda (m n)
(cond
((= m 0) (+ n 1))
((= n 0) (ackermann (- m 1) 1))
(else (ackermann (- m 1) (ackermann m (- n 1))))))))
3
6) ; ==> 509
Scheme 不是像 Lazy Racket 这样的惰性语言,因此 Y 需要稍有不同。它现在称为 Z 组合器:
#!r6rs
(import (rnrs base))
(define Z
(lambda (f)
((lambda (g)
(f (g g)))
(lambda (g)
(f (lambda args (apply (g g) args)))))))
((Z (lambda (ackermann)
(lambda (m n)
(cond
((= m 0) (+ n 1))
((= n 0) (ackermann (- m 1) 1))
(else (ackermann (- m 1) (ackermann m (- n 1))))))))
3
6) ; ==> 509
使用 delay
和 force
并没有真正使它变得更好:
#!r6rs
(import (rnrs base)
(rnrs r5rs))
(define DY
(lambda (f)
((lambda (g) (g g))
(lambda (g) (f (delay (g g)))))))
((DY (lambda (d-ackermann)
(lambda (m n)
(cond
((= m 0) (+ n 1))
((= n 0) ((force d-ackermann) (- m 1) 1))
(else ((force d-ackermann) (- m 1) ((force d-ackermann) m (- n 1))))))))
3
6) ; ==> 509
通常 Y
和 Z
允许我们命名我们的递归过程,但在最后一个中,我们得到了一个我们需要解析的承诺,因此我们泄露了实现细节并且变得更加困难使用。通常当涉及承诺时,我们希望避免不必要的执行,但调用应该 return 承诺。
有谁知道如何在 Scheme 中实现 Y 组合器,特别是惰性求值和附加参数?我的理解是 Scheme (promise?) (delay) 和 (force) 提供惰性求值支持。
据我了解,Y-combinator with application 如下所示,但由于默认情况下应用顺序评估,因此无法在 Scheme 中使用。
((lambda (f)
((lambda (x) (f (x x)))
(lambda (x) (f (x x)))))
(lambda (r) (r)))
这是一个建议的解决方案(Z 组合器),但是它使用另一个带参数的 lambda 函数作为解决方案:
;; Z-combinator
(define Z
(lambda (f)
((lambda (g) (f (g g)))
(lambda (g) (f (lambda args (apply (g g)
args)))))))
;Value: z
((Z (lambda (r)
(lambda (x)
(if (< x 2)
1
(* x (r (- x 1))))))) 5)
;Value: 120
;; end Z-combinator
根据解决方案更新
Y-combinator如下:
;; Y-combinator
(define Y
(lambda (f)
((lambda (x) (f (delay (x x))))
(lambda (x) (f (delay (x x)))))))
;Value: y
;; end Y-combinator
;; Non tail recursive
((Y (lambda (r)
(lambda (x)
(if (< x 2)
1
(* x ((force r) (- x 1)))))))
5)
;Value: 120
;; Tail - recursive
((Y (lambda (r)
(lambda (x acc)
(if (< x 2)
acc
((force r) (- x 1) (* x acc))))))
5 1)
;Value: 120
感谢您的指导!
是的,经过严格评估,自我应用程序 (x x) 会导致出现无限循环。如果你延迟这个,你可以使用 y 组合器,只要你也 'force' 在它的使用站点延迟对象:
(define (test)
(((lambda (f)
((lambda (x) (f (delay (x x))))
(lambda (x) (f (delay (x x))))))
(lambda (r)
(lambda (x)
(if (< x 2)
1
(* x ((force r) (- x 1)))))))
5))
制作在严格设置下工作的 y 组合器变体的正常方法是 eta 扩展自应用程序,这是另一种延迟它但不需要明确应用力的方法。相反,强制是由函数应用程序完成的。
普通顺序Y组合器,这里在Lazy Racket中计算(ack 3 6)
:
#lang lazy
(define Y
(lambda (f)
((lambda (g) (g g))
(lambda (g) (f (g g))))))
((Y (lambda (ackermann)
(lambda (m n)
(cond
((= m 0) (+ n 1))
((= n 0) (ackermann (- m 1) 1))
(else (ackermann (- m 1) (ackermann m (- n 1))))))))
3
6) ; ==> 509
Scheme 不是像 Lazy Racket 这样的惰性语言,因此 Y 需要稍有不同。它现在称为 Z 组合器:
#!r6rs
(import (rnrs base))
(define Z
(lambda (f)
((lambda (g)
(f (g g)))
(lambda (g)
(f (lambda args (apply (g g) args)))))))
((Z (lambda (ackermann)
(lambda (m n)
(cond
((= m 0) (+ n 1))
((= n 0) (ackermann (- m 1) 1))
(else (ackermann (- m 1) (ackermann m (- n 1))))))))
3
6) ; ==> 509
使用 delay
和 force
并没有真正使它变得更好:
#!r6rs
(import (rnrs base)
(rnrs r5rs))
(define DY
(lambda (f)
((lambda (g) (g g))
(lambda (g) (f (delay (g g)))))))
((DY (lambda (d-ackermann)
(lambda (m n)
(cond
((= m 0) (+ n 1))
((= n 0) ((force d-ackermann) (- m 1) 1))
(else ((force d-ackermann) (- m 1) ((force d-ackermann) m (- n 1))))))))
3
6) ; ==> 509
通常 Y
和 Z
允许我们命名我们的递归过程,但在最后一个中,我们得到了一个我们需要解析的承诺,因此我们泄露了实现细节并且变得更加困难使用。通常当涉及承诺时,我们希望避免不必要的执行,但调用应该 return 承诺。