让我专注于单个功能show-deck
。我知道它在做什么,但是可以稍微简化递归。使其更易于阅读可能会稍微降低效率,但我们在这里谈论的是 52 张卡片...... :)
内循环和外循环纠缠在原始代码中。这是一个将它们解开的版本:
(define (show-deck1 first-list second-list)
(define (outer-loop first-list second-list)
(cond
((null? first-list)
'())
(else
(append (inner-loop (car first-list) second-list)
(outer-loop (cdr first-list) second-list)))))
(define (inner-loop x second-list)
(cond
((null? second-list)
'())
(else
(cons (cons x (car second-list))
(inner-loop x (cdr second-list))))))
(outer-loop first-list second-list))
我们可以应用一个简化:用这种方式表达的定义,更容易看出map
可以用来做inner-loop
.
(define (show-deck2 first-list second-list)
(cond
((null? first-list)
'())
(else
(define x (car first-list))
(append (map (lambda (y) (cons x y)) second-list)
(show-deck2 (cdr first-list) second-list)))))
这使得更容易看到外部迭代的结构。我们可以map
更进一步,将它用于内部和外部循环,并用于(apply append ...)
扁平化由嵌套使用引入的子结构map
:
(define (show-deck3 first-list second-list)
(apply append
(map (lambda (x)
(map (lambda (y) (cons x y)) second-list))
first-list)))
您的版本通过巧妙地线程化计算完全避免了(apply append ...)
这些东西,但它以牺牲一些可读性为代价。避免(apply append ...)
嵌套循环结构并且仍然可以轻松查看嵌套循环结构的一种方法是使用一种foldr
方法而不是一种map
方法:
(define (foldr f acc l)
(cond
((null? l) acc)
(else
(f (car l)
(foldr f acc (cdr l))))))
(define (show-deck first-list second-list)
(foldr (lambda (x acc)
(foldr (lambda (y acc)
(cons (cons x y) acc))
acc
second-list))
'()
first-list))
这应该与您之前的原始代码相匹配。但是,它将循环性降级为foldr
,因此所有这些iter
功能都消失在foldr
.
就个人而言,如果我用完整的 Racket 编写,我只会用for
循环对其进行编码。:) 它看起来像这样:
;; If we're allowed to use full Racket:
(define (show-deck first-list second-list)
(for*/list ([x first-list]
[y second-list])
(cons x y)))