Scheme/Drracket,避免使用 let,仍然不会对同一个函数求值两次

Scheme/Drracket, avoid using let, still not evaluating same function twice

我有一个编码 class 作业我无法解决:(

(define f
  (lambda (x)
    (i (g x) (h (g x)))))

i、g 和 h 只是任意函数名称。 这是代码,我需要重写它,以便 (g x) 只被评估一次,但不使用 let (或其任何变体),仅使用 definelambda 作为预定义函数。我也不允许从 f 中进行计算,也就是说,所有计算都必须在该函数内部进行。

简单的方法是

(define f
  (lambda (x)
    (define intermediary (g x))
    (i intermediary (h intermediary))))

更复杂的是

(define f
  (lambda (x)
    ((lambda (intermediary) ; anonymous procedure
       (i intermediary (h intermediary)))
     (g x))))

或者,避免匿名过程并将其命名为 sub:

(define f
  (lambda (x)
    (define sub
      (lambda (intermediary)
       (i intermediary (h intermediary))))
    (sub (g x))))

有趣的是,不允许您使用 let 的任何变体,而 definelambda 是允许的,我肯定会说这是 let 的真正变体(反之亦然)。

(let ((v1 expr1) ...)
  body ...)

相同
((lambda (v1 ...)
   body ...) expr1 ...)

所以 letlambda 的变体。因此:

(define f
  (lambda (x)
    (let ((gx (g x)))
      (i gx (h gx)))))

当然可以改写为:

(define f
  (lambda (x)
    ((lambda (gx)
       (i gx (h gx)))
     (g x))))

现在想象一下,在 (define f ..) 之前我们定义了其他自由变量。可以改写为:

((lambda (i)
   ((lambda (h)
      ((lambda (g)
         ((lambda (f)
            rest-of-program ...)
          (lambda (x)
            ((lambda (gx)
               (i gx (h gx)))
             (g x)))))
       (lambda (v) g-expression)))
    (lambda (v) h-expression)))
 (lambda (v1 v2) i-expression))

如果其中一个绑定变量实际上需要有一个在它的闭包中更远的绑定,那么真正的扩展可能会稍微复杂一些,但对于基元来说这是可行的。