这是一个递归算法,可以生成集合的所有子集。等效的Python代码是:
def subsets(s):
if not s:
yield ()
else:
for e in subsets(s[1:]):
yield s[:1] + e
yield e
for s in subsets((1,2,3)):
print(s)
结果:
>>>
(1, 2, 3)
(2, 3)
(1, 3)
(3,)
(1, 2)
(2,)
(1,)
()
这是我试过的Racket版本:
#lang racket
(require racket/generator)
(define (subsets x)
(generator ()
(let recur ([s x])
(if (null? s)
(yield '())
(for ([e (in-producer (recur (cdr s)))])
(yield (cons (car s) e))
(yield e))))))
(for/list ([j (in-producer (subsets '(1 2 3)))])
(display j))
但它不起作用:
Welcome to DrRacket, version 6.0.1 [3m].
Language: racket; memory limit: 128 MB.
(). . result arity mismatch;
expected number of values not received
expected: 1
received: 0
values...:
在Racket文档中似乎没有相关示例是否可能,如何?
答案 0 :(得分:3)
你总体上非常接近,有一些小问题:
您使subsets
函数获取集合并返回生成器
正确,但后来你决定将身体包裹在recur
循环中
没有充分理由......你想要递归调用返回一个
生成器(用作生产者)所以你只需要打电话
subsets
。
迭代生成器的正确方法是让它返回一些 完成后的已知值,并将其用作停止值。对于 例如,最后添加一个(void)并使用它来停止。
你不应该混合for/list
和display
- 第一个用于
收集结果列表,第二个用于显示值。
切换到for
,或者只需删除display
即可返回列表
子集。
修复这些提供了工作代码:
#lang racket
(require racket/generator)
(define (subsets s)
(generator ()
(if (null? s)
(yield '())
(for ([e (in-producer (subsets (cdr s)) (void))])
(yield (cons (car s) e))
(yield e)))
(void)))
(for ([j (in-producer (subsets '(1 2 3)) (void))])
(displayln j))
两方评论:
关于奥斯卡解决方案的一个小评论:使用in-generator
可以是一个
有点混乱,因为它不是迭代生成器的方法但是
相反,它是一种创建生成器并立即迭代的方法
在它上面。
JFYI,如果你关心的话,这不是一个很好的方法 效率(而不是与发电机一起使用)。
答案 1 :(得分:2)
我认为程序可以简化一点。以下内容相当于Python中的代码,并注意我们如何使用in-generator
:
(require racket/generator)
(define (subsets s)
(if (null? s)
(yield '())
(for ([e (in-generator (subsets (cdr s)))])
(yield (cons (car s) e))
(yield e))))
这样称呼:
(for ([e (in-generator (subsets '(1 2 3)))])
(displayln e))
=> (1 2 3)
(2 3)
(1 3)
(3)
(1 2)
(2)
(1)
()