List Scheme-列表的子集

List Scheme-列表的子集,list,scheme,racket,List,Scheme,Racket,我需要编写一个函数来生成给定列表的所有子集。我有一个使用map的递归版本,但作为奖励,我被要求创建一个不使用显式递归、局部或任何抽象列表函数的函数。我可以使用cons,empty?,empty,first,rest和cond。我快崩溃了,有什么建议吗?我应该为需要执行的每个递归使用lambda语句吗 嗯,如果没有任何递归的话,这听起来是相当困难的。是否允许您使用此处描述的letrec 如果允许的话,这可以为您做到,但我不确定。根据您的回答,这里的想法似乎是使用一个“fold”函数,而不是在代码中

我需要编写一个函数来生成给定列表的所有子集。我有一个使用map的递归版本,但作为奖励,我被要求创建一个不使用显式递归、局部或任何抽象列表函数的函数。我可以使用
cons
empty?
empty
first
rest
cond
。我快崩溃了,有什么建议吗?我应该为需要执行的每个递归使用lambda语句吗

嗯,如果没有任何递归的话,这听起来是相当困难的。是否允许您使用此处描述的letrec


如果允许的话,这可以为您做到,但我不确定。根据您的回答,这里的想法似乎是使用一个“fold”函数,而不是在代码中进行递归调用。如果你对“折叠”足够熟悉,这不是不可能的。从本质上讲,您需要对流程进行建模,首先考虑流程中每个步骤需要计算哪些信息,然后考虑如何将新信息与旧信息结合起来

我想你最好的办法是写下:

(define (all-subsets l) (foldl ..?.. ..?.. l))

。。。然后盯着它看,直到你能为组合/辅助函数想出一个好名字。请记住,helper函数本身可能使用fold或map。为这个helper函数选择正确的名称是大多数困难/创造性的工作所在。

我非常怀疑你的教授是否要求你创建或使用Y-Combinator来解决这个问题,但是如果你想尝试这样做,下面的一些代码可能会有所帮助。用外行的话来说,y组合子是一种不用定义任何东西就可以生成函数的方法,它使用了lambda演算的能力。如果您有一个工作定义(您提到您有),那么将其转换为lambdas并不太困难。下面我将介绍这些步骤,并尽我最大的努力对其进行解释,但这是一个非常困难的概念,也是函数式编程中最“令人兴奋”的想法之一

以下是一个通常定义的函数,它将返回给定列表的长度:

;; mylength : [listof Any] -> Number
;; returns the length of xs
(define (mylength xs)
  (if (empty? xs)
      0
      (+ 1 (mylength (rest xs)))))
现在,要开始脱离定义和显式递归的标准领域,让我们创建一个lambda表达式,给定一个能够确定列表长度的函数,该表达式返回给定列表的长度,
ys

;; ys is a [Listof Any]
;; mylength is a function that returns the length of a list
(λ (ys)
  (cond [(empty? ys) 0]
        [else (+ 1 (mylength (rest ys)))]))
这段代码的问题是我们根本不希望代码中包含
mylength
。为了让您正确思考,请记住此lambda函数的全部要点是返回给定列表的长度。这看起来像是一个隐晦的信息,但你会在几行中看到我的意思

无论如何,仅使用lambda表示此定义的下一步是使length函数成为lambda函数的参数,如下所示:

;; ys is a [Listof Any]
(λ (len ys)
  ;; if ys is empty, return 0.
  (if (empty? ys) 0
      ;; otherwise, call len again, passing len itself as it's 1st argument.
      (+ 1 (len len (rest ys)))))
在代码末尾看到这一行可能会让人困惑:
(+1(len-len(rest ys kаа))
毕竟,
len
是一个只获取列表并返回其长度的函数,对吗错误。我们没有一个函数可以获取列表并返回其长度-我们不能使用像这里提到的第一个
mylength
函数那样的函数。我们需要一些其他函数,其目的是返回列表的长度。如果你还记得我“神秘地”说了几句话

请记住,此lambda函数的整个要点是返回给定列表的长度

所以,如果这个lambda函数返回给定列表的长度,而我们需要的函数返回给定列表的长度…哇。你在想我在想什么吗

((λ (len ys) (if (empty? ys) 0 
                  (+ 1 (len len (rest ys)))))
  (λ (len xs) (if (empty? xs) 0
                  (+ 1 (len len (rest xs))))) '(your list here))
“什么!?”你可能在想——“你能做到!”

我的朋友,答案是肯定的。是的,你可以。如果您迷路了,请仔细、认真地查看上面的代码。让我们调用外部lambda函数
func 1
,以及内部lambda函数
func 2
func 1
与我们以前编写的函数相同。那部分有道理,对吧
func 1
使用其他函数
len
和列表
ys
,并尝试返回
ys
的长度。由于
func 1
len
的用途与
func 1
的用途相同,因此我们可以将本质上是
func 1
的内容传递为外部lambda的
len
参数

为了更好地理解它,让我们将列表中的
”(1)
传递给我们新的、怪异的lambda怪物:

第一步:

(空?'(1))->FALSE

外部lambda确定
”(1)
不是空的,因此它计算下一步

`(+1(len-len(rest)(1)))

(rest'(1))
计算结果为

(+1(len-len-empty))

len等于

(λ(len xs)(如果(空?xs)0
(+1(len-len(rest xs‘‘‘‘)’)
,因此上述内容扩展为:

((λ (len ys) (if (empty? ys) 0 
                  (+ 1 (len len (rest ys)))))
  (λ (len xs) (if (empty? xs) 0
                  (+ 1 (len len xs)))) empty)
然后,
empty
作为
ys
通过外部lambda,并计算第一个条件语句:

(空?ys)

(空?空)->TRUE

因此
(len len empty)
调用返回
0
。现在进入下一步:

(+1 0)”,其计算结果为
1
,即列表的长度
”(1)`

这是一个很难理解的概念,我不认为我在解释这个概念方面做得很好,因为我帮助您完成了识别它所需的步骤。如果你理解了Y-Combinator是如何工作的,我会留下深刻的印象——你理解我的闲话的能力,以及我解释如此混乱概念的能力

 1. (empty? '(1)) -> FALSE
 2. (+ 1 (len len (rest ys)))

((λ (len ys) (if (empty? '(1)) 0 
                  (+ 1 (len len (rest ys)))))
  (λ (len xs) (if (empty? xs) 0
                  (+ 1 (len len (rest xs))))) '(your list here))
W