在计划中实施powerset

时间:2017-03-18 12:09:57

标签: scheme fold powerset

我试图以两种方式在Scheme中实现powerset函数。 一种方法是使用尾递归,我这样做:

(define (powerset list)
 (if (null? list) '(())                                    ;; if list is empty, its powerset is a list containing the empty list
  (let ((rest (powerset (cdr list))))                   ;; define "rest" as the result of the recursion over the rest of list
    (append (map (lambda (x) (cons (car list) x)) rest) ;; add the first element of list to the every element of rest (which is a sublist of rest) 
            rest))))                                    ;; and append it to rest itself (as we can either use the current element (car list), or not

哪种方法正常。

另一种方法是使用 foldr ,这是我遇到一些问题的地方。 我目前的实施如下:

(define (powerset-fr list)
 (foldr (lambda (element result)        ;; This procedure gets an element (and a result);
       (if (null? result) ;; if starting with the empty list, there is nothing to "fold over".
           (cons '() (cons element result))
           (foldr (lambda (inner-element inner-result)
                    (append (cons element result) inner-result))
                  '(())
                  result)))
     '()                             ;; The result is initialized to the empty list,
     list))                         ;; and the procedure is being applied for every element in the first list (list1)

结果不佳。

我会尽快解释到目前为止我是如何解决这个问题的:

foldr遍历给定集合中的每个元素。对于每个这样的元素,我应该向powerset添加一些新元素。 这些元素应该是哪些? powerset中每个现有元素的一个新元素,其中将列表中的当前元素追加到powerset中的现有元素。

这就是为什么我认为我应该以嵌套的方式使用foldr 两次 - 一个用于遍历给定列表中的所有项目,并且对于每个项目,我使用foldr来遍历“结果中的所有项目” “(当前的powerset)。

我遇到了空列表的问题(没有添加到powerset中),因此添加了“if”部分(而不仅仅是foldr),但它也不能很好地工作。

我认为就是这样。我感觉很亲密,但仍然非常具有挑战性,所以每一个帮助都会受到欢迎。 谢谢!

1 个答案:

答案 0 :(得分:2)

解决方案更简单,不需要使用双foldr,试试这个:

(define (powerset-fr lst)
  (foldr (lambda (e acc)
           (let ((rst (powerset-fr (cdr lst))))
             (append (map (lambda (x) (cons e x))
                          rst)
                     rst)))
         '(())
         lst))

如果你的口译员定义了append-map或等价的东西,那么解决方案就会缩短一点 - 结果会有不同的顺序,但这并不重要:

(define (powerset-fr lst)
  (foldr (lambda (e acc)
           (append-map (lambda (x) (list x (cons e x)))
                       (powerset-fr (cdr lst))))
         '(())
         lst))

无论哪种方式,它都按预期工作:

(powerset-fr '(1 2 3))
=> '((1 2 3) (1 2) (1 3) (1) (2 3) (2) (3) ())