Recursion 如何在Racket中仅使用lambda进行递归?

Recursion 如何在Racket中仅使用lambda进行递归?,recursion,lambda,functional-programming,scheme,racket,Recursion,Lambda,Functional Programming,Scheme,Racket,我需要一些帮助,试图找出如何使下面的代码只使用lambdas进行递归 (define (mklist2 bind pure args) (define (helper bnd pr ttl lst) (cond [(empty? lst) (pure ttl)] [else (define (func t) (helper bnd pr (append ttl (list t)) (rest lst))) (bind (first lst)

我需要一些帮助,试图找出如何使下面的代码只使用lambdas进行递归

(define (mklist2 bind pure args)
  (define (helper bnd pr ttl lst)
    (cond [(empty? lst) (pure ttl)]
          [else (define (func t) (helper bnd pr (append ttl (list t)) (rest lst)))
           (bind (first lst) func)])
    )
  (helper bind pure empty args))


给定一个示例
事实
程序-

(define fact
  (lambda (n)
    (if (= n 0)
        1
        (* n (fact (- n 1)))))) ;; goal: remove reference to `fact`

(print (fact 7)) ; 5040
上面的
fact
(lambda(n)
,当我们调用
fact
时,我们需要这个lambda,这样我们可以用新参数重新应用它
lambda
是匿名的,如果我们不能使用顶级的
define
绑定,绑定变量的唯一方法就是使用lambda的参数。想象一下-

(lambda (r)
  ; ...lambda body...
  ; call (r ...) to recur this lambda
)
我们只需要
一些东西
就可以让我们的
(lambda(r)…
这样做-

(something (lambda (r)
  (print 1)
  (r)))

; 1
; 1
; 1
; ... forever
这个
东西
非常接近
U
组合器-

(define u
  (lambda (f) (f f)))

(define fact
  (lambda (r)     ;; wrap in (lambda (r) ...)
    (lambda (n)
      (if (= n 0)
          1
          (* n ((r r) (- n 1))))))) ;; replace fact with (r r)

(print ((u fact) 7))

; => 5040
现在递归是通过使用参数实现的,我们可以有效地删除所有
define
绑定,并且只使用
lambda
-

; ((u fact) 7)
(print (((lambda (f) (f f))  ; u
         (lambda (r)         ; fact
           (lambda (n)
             (if (= n 0)
                 1
                 (* n ((r r) (- n 1)))))))
        7))

; => 5040
; (((u y) fact) 7)
(print ((((lambda (f) (f f))   ; u
          (lambda (r)          ; y
            (lambda (f)
              (f (lambda (x) (((r r) f) x))))))
         (lambda (recur)       ; fact
           (lambda (n)
             (if (= n 0)
                 1
                 (* n (recur (- n 1)))))))
        7))

; => 5040

U-combinator很简单,但是必须在函数内部调用
((r)…)
是很麻烦的。如果你能打电话给
(r…
,直接重复,那就太好了。这正是Y组合子所做的-

(define y
  (lambda (f)
    (f (lambda (x) ((y f) x))))) ;; pass (y f) to user lambda

(define fact
  (lambda (recur)
    (lambda (n)
      (if (= n 0)
          1
          (* n (recur (- n 1))))))) ;; recur directly

(print ((y fact) 7))

; => 5040
但是看看
y
是如何有一个按名称递归定义的?我们可以使用
u
删除by-name引用,并使用
lambda
参数重新出现。和我们上面做的一样-

(define u
  (lambda (f) (f f)))

(define y
  (lambda (r)      ;; wrap in (lambda (r) ...)
    (lambda (f)
      (f (lambda (x) (((r r) f) x)))))) ;; replace y with (r r)

(define fact
  (lambda (recur)
    (lambda (n)
      (if (= n 0)
          1
          (* n (recur (- n 1)))))))

(print (((u y) fact) 7)) ;; replace y with (u y)

; => 5040
我们现在只能使用
lambda
-

; ((u fact) 7)
(print (((lambda (f) (f f))  ; u
         (lambda (r)         ; fact
           (lambda (n)
             (if (= n 0)
                 1
                 (* n ((r r) (- n 1)))))))
        7))

; => 5040
; (((u y) fact) 7)
(print ((((lambda (f) (f f))   ; u
          (lambda (r)          ; y
            (lambda (f)
              (f (lambda (x) (((r r) f) x))))))
         (lambda (recur)       ; fact
           (lambda (n)
             (if (= n 0)
                 1
                 (* n (recur (- n 1)))))))
        7))

; => 5040

通过使用currying,如果需要,我们可以扩展函数以支持更多参数-

(define range
  (lambda (r)
    (lambda (start)
      (lambda (end)
        (if (> start end)
            null
            (cons start ((r (add1 start)) end)))))))

(define map
  (lambda (r)
    (lambda (f)
      (lambda (l)
        (if (null? l)
            null
            (cons (f (car l))
                  ((r f) (cdr l))))))))

(define nums
  ((((u y) range) 3) 9))

(define squares
  ((((u y) map) (lambda (x) (* x x))) nums))

(print squares)
; '(9 16 25 36 49 64 81)
作为单个
lambda
表达式-

; ((((u y) map) (lambda (x) (* x x))) ((((u y) range) 3) 9))
(print (((((lambda (f) (f f)) ; u
           (lambda (r)        ; y
             (lambda (f)
               (f (lambda (x) (((r r) f) x))))))
          (lambda (r)         ; map
            (lambda (f)
              (lambda (l)
                (if (null? l)
                    null
                    (cons (f (car l))
                          ((r f) (cdr l))))))))
         (lambda (x) (* x x))) ; square
        (((((lambda (f) (f f)) ; u
            (lambda (r)        ; y
              (lambda (f)
                (f (lambda (x) (((r r) f) x))))))
           (lambda (r)         ; range
             (lambda (start)
               (lambda (end)
                 (if (> start end)
                     null
                     (cons start ((r (add1 start)) end)))))))
          3)   ; start
         9)))  ; end

; => '(9 16 25 36 49 64 81)

使用


仅使用lambda的递归可以使用来完成,最简单的是


但是,要考虑到这样一个组合符的类型是无限长的,因此如果使用类型编程,则该类型是递归的,并且具有无限长。不是每个类型检查器都能够计算递归类型的类型。球拍的类型检查器我想它是,我记得它不能运行定点组合器,但不确定。你必须禁用类型检查器才能工作。

为了回应@alinsoar的回答,我只想表明,如果你使用类型添加正确的类型注释,Typed Racket的类型系统可以表示Y组合符

U组合符的参数需要一个类型:

(: u (All (a) (-> (Rec F (-> F a)) a)))
(define u
  (lambda (f) (f f)))
Y组合器本身在其类型中不需要a:

(: y (All (a b) (-> (-> (-> a b) (-> a b)) (-> a b))))
但是,Y combinator的定义需要对其中使用的函数之一进行类型注释:

(: y (All (a b) (-> (-> (-> a b) (-> a b)) (-> a b))))
(define y
  (lambda (f)
    (u (lambda ([g : (Rec G (-> G (-> a b)))])
         (f (lambda (x) ((g g) x)))))))

在没有嵌套的递归定义的情况下,您可以对简单的情况执行此操作吗?如果不是的话,也许先问问这个问题,然后从那里开始构建?球拍的类型检查器不是辛德利·米尔纳。问题是关于标准的非类型球拍,而不是类型球拍。类型化Racket的类型检查器也不是Hindley Milner,IIRC它可以表示Y组合符,尽管只有类型注释。但我想我已经偏离了一个与原始问题无关的正切,
Ω
是一个不动点组合子吗?它不是
Ωf=f(Ωf)
,而是
Ωf=Ωf
@williness I,尽管
Ω=((λ(x)(x)(λ(x)(x))
。你有两个不平衡的参数,所以不清楚你到底在想什么。好吧,那是Ω,这就是我首先提到的。它减少到Ω,然后又减少到Ω,等等。这意味着Ωf=Ωf,而不是f(Ωf)就像任何不动点组合符应该是的一样。谢谢你分享这个Alex。我没有花足够的时间在我的脑海里,我想修改
omega=((λ(x)(x)(λ(x)(x))
并让它递归地计算你需要的函数……但是,是的,欧米茄本身不是一个定点组合器,但它可以计算任何递归函数。
Y
是能够计算任何递归的最简单的定点组合器吗?@alinsoar什么可以计算?它发散,所以看起来它什么都不能计算。
O=>O
。您的注释中的术语有两个不平衡的圆括号,因此,不清楚它应该是什么。@Willenss添加了一些模式参数而不是仅添加X,添加了一些终止条件而不是(X),等等。。。
(: y (All (a b) (-> (-> (-> a b) (-> a b)) (-> a b))))
(define y
  (lambda (f)
    (u (lambda ([g : (Rec G (-> G (-> a b)))])
         (f (lambda (x) ((g g) x)))))))