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)…))))
。正如你所做的那样,在后面的回答中: