这个答案是@rnso 的代码的一系列翻译,修改为使用递归辅助函数而不是重复的set!。
#lang racket
(define (cpermit sl)
;; n starts at (length sl) and goes towards zero
;; sl starts at sl
;; outl starts at '()
(define (loop n sl outl)
(cond [(zero? n) outl]
[else
(loop (sub1 n) ; the new n
(append (rest sl) (list (first sl))) ; the new sl
(cons sl outl))])) ; the new outl
(loop (length sl) sl '()))
> (cpermit (list 1 2 3 4))
(list (list 4 1 2 3) (list 3 4 1 2) (list 2 3 4 1) (list 1 2 3 4))
对于这种递归帮助器的简写,您可以使用命名为let。这会将初始值放在顶部,以便于理解。
#lang racket
(define (cpermit sl)
(let loop ([n (length sl)] ; goes towards zero
[sl sl]
[outl '()])
(cond [(zero? n) outl]
[else
(loop (sub1 n) ; the new n
(append (rest sl) (list (first sl))) ; the new sl
(cons sl outl))]))) ; the new outl
> (cpermit (list 1 2 3 4))
(list (list 4 1 2 3) (list 3 4 1 2) (list 2 3 4 1) (list 1 2 3 4))
对于@rnso,您可以认为n、sl 和outl 与“可变变量”具有相同的目的,但这实际上与我之前定义@ 时编写的代码相同987654328@ 作为递归辅助函数。
上述模式对于 Scheme/Racket 代码中的累加器非常常见。每次你想要这样的循环时,(cond [(zero? n) ....] [else (loop (sub1 n) ....)]) 写出来有点烦人。因此,您可以将for/fold 与两个累加器一起使用。
#lang racket
(define (cpermit sl)
(define-values [_ outl]
(for/fold ([sl sl] [outl '()])
([i (length sl)])
(values (append (rest sl) (list (first sl))) ; the new sl
(cons sl outl)))) ; the new outl
outl)
> (cpermit (list 1 2 3 4))
(list (list 4 1 2 3) (list 3 4 1 2) (list 2 3 4 1) (list 1 2 3 4))
您可能已经注意到,外部列表的最后一个是(list 1 2 3 4),倒数第二个是(list 2 3 4 1),等等。这是因为我们通过在前面添加@ 来从后到前构建列表987654334@。为了解决这个问题,我们可以在最后反转它。
#lang racket
(define (cpermit sl)
(define-values [_ outl]
(for/fold ([sl sl] [outl '()])
([i (length sl)])
(values (append (rest sl) (list (first sl))) ; the new sl
(cons sl outl)))) ; the new outl
(reverse outl))
> (cpermit (list 1 2 3 4))
(list (list 1 2 3 4) (list 2 3 4 1) (list 3 4 1 2) (list 4 1 2 3))
最后,(append (rest sl) (list (first sl))) 应该是它自己的辅助函数,因为它有一个明确的目的:旋转列表一圈。
#lang racket
;; rotate-once : (Listof A) -> (Listof A)
;; rotates a list once around, sending the first element to the back
(define (rotate-once lst)
(append (rest lst) (list (first lst))))
(define (cpermit sl)
(define-values [_ outl]
(for/fold ([sl sl] [outl '()])
([i (length sl)])
(values (rotate-once sl) ; the new sl
(cons sl outl)))) ; the new outl
(reverse outl))
> (cpermit (list 1 2 3 4))
(list (list 1 2 3 4) (list 2 3 4 1) (list 3 4 1 2) (list 4 1 2 3))