繁体   English   中英

是否可以在球拍中创建匿名递归 function

[英]is it possible to create an anonymous recursive function in racket

如果我有这样的递归 function :

(define (double-n-times x n)
  (if (= n 0)
      x
      (double-n-times (* 2 x) (- n 1))))

我怎样才能制作它的 lambda 版本而不给它命名? ...就像我想在某处内联它一样。 那可能吗? (我的意思是在这种情况下我可以使用 fold - 所以这个例子可能不是那么好) - 是否有某种我无法找到的“自我”符号或占位符? 或者你只需要给它一个名字。

Racket 中的 Y-Combinator 是:

(lambda (f)
    ((lambda (h) (h h))
     (lambda (g) (f (lambda args (apply (g g) args))))))

这个 function 可以采用任何匿名 function 并将其递归地应用于自己。

让我们定义您的功能部分。 double-n-times部分仅用 lambdas 编写:

(lambda (f)
    (lambda (x n)
      (if (= n 0) x (f (* 2 x) (- n 1))))))

其中f我们可以随意命名 - 所以我们也可以称它为double-n-part

如果我们对此应用 Y-Combinator,我们得到:

((lambda (f)
    ((lambda (h) (h h))
     (lambda (g) (f (lambda args (apply (g g) args))))))
  (lambda (f)
    (lambda (x n)
      (if (= n 0) x (f (* 2 x) (- n 1))))))

这会吐出一个 function ,它采用 arguments xn并将第二个定义的内部 function 应用于它们。

所以现在,没有任何命名函数 - 只使用lambda表达式 - 你可以应用在你的 arguments 上 - 假设x=3n=4

(((lambda (f)
    ((lambda (h) (h h))
     (lambda (g) (f (lambda args (apply (g g) args))))))
  (lambda (f)
    (lambda (x n)
      (if (= n 0) x (f (* 2 x) (- n 1))))))
 3 4)
;;=> 48 ; as expected (3 * 2 * 2 * 2 * 2)

这样阅读更方便。 但是,当我们只允许单子函数(只有一个参数的函数)而不是可变参数时,我们也可以在没有applyargs的情况下定义Y combinator子。 然后它看起来像这样(我们必须像这样一个接一个地给arguments):

((((lambda (f)
      ((lambda (h) (h h))
        (lambda (g) (f (lambda (x) ((g g) x))))))
    (lambda (f)
      (lambda (x)
        (lambda (n)
          (if (= n 0) x ((f (* 2 x)) (- n 1)))))))
 3) 4)
;;=> 48

您的问题的答案是肯定的,通过使用宏。 但在我说这个之前,我必须先问这个:你问是因为你只是好奇吗? 或者你问是因为有一些问题,比如你不想用名字污染命名空间?

如果您不想用名称污染命名空间,您可以简单地使用局部构造,例如命名为letletrec ,甚至是 Y 组合器。 或者,您可以将define包裹在(let ()...)内。

(let ()
  (define (double-n-times x n)
    (if (= n 0)
        x
        (double-n-times (* 2 x) (- n 1))))
  (double-n-times 10 10))

;; double-n-times is not in scope here

对于实际答案:这是一个类似于lambda的宏rlam ,但它允许您使用self来引用自身:

#lang racket

(require syntax/parse/define)

(define-syntax-parse-rule (rlam args body ...+)
  #:with self (datum->syntax this-syntax 'self)
  (letrec ([self (λ args body ...)])
    self))

;; compute factorial of 10
((rlam (x)
   (if (= 0 x)
       1
       (* x (self (sub1 x))))) 10) ;=> 3628800

是的。 作为名称的占位符是lambda 函数的参数用于:

(define (double-n-times x n)
  (if (= n 0)
      x
      (double-n-times (* 2 x) (- n 1))))
=
(define double-n-times (lambda (x n)
  (if (= n 0)
      x
      (double-n-times (* 2 x) (- n 1)))))
=
(define double-n-times (lambda (self)   ;; received here
                         (lambda (x n)
  (if (= n 0)
      x
      (self (* 2 x) (- n 1))))))       ;; and used, here

但是这个“ self ”参数什么? 它是 lambda function本身

= ;; this one's in error:
(define double-n-times ((lambda (u)   ;; call self with self
                          (u u))   ;; to receive self as an argument
                  (lambda (self)
                    (lambda (x n)
  (if (= n 0)
      x
      (self (* 2 x) (- n 1)))))))
  ;; can you see where and why?

= ;; this one isn't:
(define double-n-times ((lambda (u) (u u))
                  (lambda (self)
                    (lambda (x n)
  (if (= n 0)
      x
      ((self self) (* 2 x) (- n 1)))))))

 ;; need to call self with self to actually get that 
 ;; (lambda (x n) ... ) thing to be applied to the values!

现在它起作用了: (double-n-times 1.5 2)返回6.0

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM