如何在 scheme/racket 中使用 unfold 编写 Collat​​z 序列?

how to write Collatz sequence using unfold in scheme/racket?

以常规方式编写 Collat​​z 序列生成函数后:

(define (colatz-seq #;starting@ n)
  (cond ((= n 1) '())
        ((even? n) (cons (/ n 2) (colatz-seq (/ n 2))))
        ((odd? n) (cons (+ (* n 3) 1) (colatz-seq (+ (* n 3) 1))))))

我想用unfold来写:

(define (next-colatz-step n)
  (cond ((even? n) (/ n 2))
        ((odd? n) (+ (* n 3) 1))))

(define (one? n)
  (= n 1))

(define (colatz-seq #;starting@ n)
  (unfold one? next-colatz-step next-colatz-step n))

它按预期工作但是我无法在不使用 "next-colatz-step" 作为展开的第二个和第三个参数的情况下使其工作。为什么? 为两个参数提供相同的参数似乎有点奇怪。

请注意,在您的两个解决方案中,您都排除了序列中的起始元素,并且在基于 unfold 的解决方案中,生成的序列以某种方式落后于一个位置,这就是为什么您必须通过 next-colatz-step 两次。

如果我们从给定的 n 数字开始,unfold 的第二个参数就是 identity 过程,这看起来更自然。但这给我们留下了最后一个值(应该总是 1,假设 Collat​​z 猜想为真)现在丢失的问题。这就是为什么现在我们必须提供一个额外的过程来生成列表的尾部。试试这个:

(require srfi/1)

(define (one? n)
  (= n 1))

(define (next-collatz-step n)
  (cond ((even? n) (/ n 2))
        (else (+ (* 3 n) 1))))

(define (last-value n)
  (list n))

(define (collatz-seq n)
  (unfold one? identity next-collatz-step n last-value))

(collatz-seq 10)
=> '(10 5 16 8 4 2 1)