Lambda 在一个函数中生成powerset,没有显式递归,并且在Racket中只使用最简单的原语

Lambda 在一个函数中生成powerset,没有显式递归,并且在Racket中只使用最简单的原语,lambda,scheme,lisp,racket,anonymous-recursion,Lambda,Scheme,Lisp,Racket,Anonymous Recursion,注意:这是家庭作业的额外奖励,但我花了太长时间尝试了一些没有用的东西。非常感谢你的帮助,但我想这不是必要的 前提: 为数字列表生成功率集,但不使用任何辅助程序、显式递归、循环或函数/常量,而不是cons、first、rest、empty?、empty、else、lambda和cond,在语言层面上只使用一个定义,而中间学生使用Lambda。动力装置的顺序无关紧要 到目前为止我所尝试的: 我发现了Y-combinator和匿名递归,这要归功于(作者有相同的最终目标,但我们有不同的方法,因此他文章中

注意:这是家庭作业的额外奖励,但我花了太长时间尝试了一些没有用的东西。非常感谢你的帮助,但我想这不是必要的

前提: 为数字列表生成功率集,但不使用任何辅助程序、显式递归、循环或函数/常量,而不是
cons
first
rest
empty?
empty
else
lambda
cond
,在语言层面上只使用一个
定义
,而中间学生使用Lambda
。动力装置的顺序无关紧要

到目前为止我所尝试的: 我发现了Y-combinator和匿名递归,这要归功于(作者有相同的最终目标,但我们有不同的方法,因此他文章中的信息并不能解决我的问题),以及
powerset
代码,我据此写了以下内容:

(define (powerset aL)
  (((lambda (X)
      ((lambda (proc)
         (proc proc))
       (lambda (proc)
         (X (lambda (arg)
              ((proc proc) arg))))))
    (lambda (subset)
      (lambda (lst)
        (cond
          [(empty? lst) (list empty)]
          [else (combine (first aL) (powerset (rest aL)))])))) aL)

(define (combine a r)
  (cond
    [(empty? r)  empty]
    [else (cons (cons a (first r)) (cons (first r) (combine a (rest r))))]))
我正在通过运行以下命令来测试此代码:

(check-expect (powerset '(1 2 3)) 
(list '(1 2 3) '(2 3) '(1 3) '(3) '(1 2) '(2) '(1) '()))
这段代码运行并产生正确的结果,但正如您所看到的,我仍然依赖于外部辅助函数,
combine
,我不知道如何将其转换为
lambda
,因为据我所知,Y-combinator只使用一个参数,而
combine
需要2个参数。也许我对这个问题的逻辑或方法是有缺陷的。我在
lambda
方面的经验有限,因此我可能也缺少相关知识

我需要帮助的内容:关于下一步的任何建议,帮助我将
整合到
powerset
中,为正确的逻辑/方法提供提示/线索,或者提供解决方案,我们将不胜感激

提前谢谢

Y组合器仅适用于一个参数,组合器需要2个参数

任何多参数函数都可以想象为一个单参数函数,返回等待下一个参数的lambda。这个过程叫做咖喱。例如,如果我们有

(define add (x y)
  (+ x y))
我们可以这样称呼它

(add 2 2)
很简单。现在我们来做咖喱:

(define (add x)
  (lambda (y)
    (+ x y)))
调用它需要稍微不同的语法,但基本思想相同:

((add 2) 2)

如果您希望使其适用于Y组合器,您可以将相同的概念应用于任何lambda。

我发现下面的技巧比使用Y更容易理解。我认为它与U有关(我也发现比Y更容易理解)

这可能不足以满足“不显式递归”的要求,尽管我认为是这样

如果您有一些“想要”自由使用自身的函数,以便可以递归,例如:

(define powerset
  (λ (set)
    (cond [(empty? set)
           (list empty)]
          [else
           (combine (first set)
                    (powerset (rest set)))])))
然后,您可以将其转换为一个函数,该函数接受一个附加参数,并调用该参数:

(define powerset/c
  (λ (ps/c set)
    (cond [(empty? set)
           (list empty)]
          [else
           (combine (first set)
                    (ps/c ps/c (rest set)))])))
/c
名称是因为当我发现这个技巧时,我认为这个参数是一个延续,但我认为那是因为我不知道延续到底是什么

现在(使用
组合的定义)
(powerset/c powerset/c'(x y z))
将计算
(x y z)
的幂集,并且没有显式递归

嗯,这很难看,但这很容易修复使用

(define powerset
  (λ (set)
    ((λ (powerset/c)
       (powerset/c powerset/c set))
     (λ (ps/c set)
       (cond [(empty? set)
              (list empty)]
             [else
              (combine (first set)
                       (ps/c ps/c (rest set)))])))))
然后诀窍是以这种方式编写
组合
,然后在本地使用它,并使用

(define powerset
  (λ (set)
    ((λ (combine)
       ((λ (powerset/c)
          (powerset/c powerset/c set))
        (λ (ps/c set)
          (cond [(empty? set)
                 (list empty)]
                [else
                 (combine (first set)
                          (ps/c ps/c (rest set)))]))))
     <combine defn here>)))
(定义动力集
(λ(集)
((λ(联合)
((λ(功率集/c)
(动力装置/动力装置/动力装置)
(λ(ps/c组)
(条件[(空?集)
(列表为空)]
[其他
(联合收割机(第一套)
(ps/c ps/c(其余套件)))]
)))

在lambda演算中,所有函数都是一元函数

这意味着

(define (combine a r)
  (cond
    [(empty? r)  empty]
    [else (cons (cons a (first r))
                (cons (first r) 
                      (combine a (rest r))))]))
将写为

(λ (combine)
  (λ (a)
    (λ (r)
      (cond
        [(empty? r) empty]
        [else (cons (cons a (first r))
                    (cons (first r) 
                          ((combine a) (rest r))))]))))
考虑到这一点,以下是解决方案:

(define powerset
  ((λ (y)
     ((λ (f) (y (λ (x) ((f f) x))))
      (λ (f) (y (λ (x) ((f f) x))))))
   
   (λ (ps)
     (λ (set)
       (cond
         [(empty? set) (cons empty empty)]
         [else ((((λ (y)
                    ((λ (f) (y (λ (x) ((f f) x))))
                     (λ (f) (y (λ (x) ((f f) x))))))
                  
                  (λ (combine)
                    (λ (a)
                      (λ (r)
                        (cond
                          [(empty? r) empty]
                          [else (cons (cons a (first r))
                                      (cons (first r) 
                                            ((combine a) (rest r))))])))))
                 (first set))
                (ps (rest set)))])))))

一般来说,如果你已经解决了你的问题,你应该用回答按钮说:评论不是为了回答。回答自己的问题是可以接受的(甚至是被鼓励的!)。只要写下你希望别人写的答案。我很好奇,你是从其他地方还是从其他地方得到你的原始
powerset
代码(使用Y combinator转换之前的代码)?(转换是错误的,顺便说一句,没有使用Y设置的函数,而是通过显式递归调用
powerset
。@amalloy教授对代码共享很严格,我会在作业到期后共享代码!是的,我确实从那里得到了逻辑,因为我最初的解决方案使用了
foldr
map
,使用匿名递归很难复制。我还意识到,在编写最终版本时,我的代码使用了显式递归,我已经纠正了这个错误,最终代码只使用了带有
lambda
的匿名递归。感谢所有的提示和答案!是的,Y的全部目的是为了避免一个人为了递归调用而显式地编写
(fx)
,我想没有别的了。可惜他们在书中没有说那么多,反而使它变得如此复杂,而实际上它非常简单。在Q中OP链接的条目上,很好地呈现了相同的想法。”
(定义(合并a r)
将被写成“
(λ(合并)(λ(a)(λ(r)…))))
。正如你所做的那样,在后面的回答中: