Clojure在Racket中的迭代函数相当于什么



我今天正在玩Racket,并试图基于同一函数的多个应用程序生成一个不确定的数字序列。

在Clojure中,我会使用迭代函数来实现这一点,但我不确定在Racket中等效的是什么。

SRFI 41 ((require srfi/41))直接提供stream-iterate

您可以使用Óscar的示例并在看到iterate的地方替换stream-iterate,而不必定义自己的iterate。此外,您可以使用match-lambda:

模拟Clojure的参数解构。
(require srfi/41)
(define fib
  (stream-map first
              (stream-iterate (match-lambda
                                ((list a b)
                                 (list b (+ a b))))
                              '(0 1))))
(stream->list 10 fib)  ; => (0 1 1 2 3 5 8 13 21 34)

在大多数情况下,您可以用for/fold代替iterate的使用。

> (define (mult2 x) (* x 2))
> (for/fold ([x 1])   ; the initial value of x is 1
            ([i 8])   ; count i=0,...,7
   (mult2 x))         ; put x = (mult2 x)
256

for/fold的优点是一次可以迭代更多的变量:

(define (mult2 x) (* x 2))
(define (div2 x)  (/ x 2))
(for/fold ([x 1]        ; bind x to 1
           [y 1])       ; bind y to 1
          ([i 8])       ; i=0,...,7
  (values (mult2 x)     ; put x = (mult2 x)
          (div2  y)))   ; put y = (div2 y)

返回两个值:2561/256

收集元素很容易。下面是斐波那契的例子:

(for/fold ([fs '(1)]     ; list of fibonacci numbers generated so far
           [f1   1]      ; a fibonacci number
           [f2   1])     ; the following fibonacci number
          ([i   10])     ; i = 0,...,9
  (values (cons f2 fs)   ; cons the new fibonacci number to the list fs
          f2             ; put f1 = (the old) f2
          (+ f1 f2)))    ; put f2 = (the old) f1+f2

结果由三个值组成:

'(89 55 34 21 13 8 5 3 2 1 1)
89
144

在内置的Racket过程中没有直接的等效,但是我们可以使用流实现具有类似功能的东西。试试这个:

(define (stream-take m s)
  (if (zero? m)
      '()
      (cons (stream-first s)
            (stream-take (sub1 m) (stream-rest s)))))
(define (iterate f x)
  (stream-cons x (iterate f (f x))))

例如,以下是Clojure文档中的示例在Racket中的样子:

(stream-take 5 (iterate add1 5))
=> '(5 6 7 8 9)
(stream-take 10 (iterate (curry + 2) 0))
=> '(0 2 4 6 8 10 12 14 16 18)
(define powers-of-two (iterate (curry * 2) 1))
(stream-ref powers-of-two 10)
=> 1024
(stream-take 10 powers-of-two)
=> '(1 2 4 8 16 32 64 128 256 512)
(define fib
  (stream-map first
              (iterate (lambda (pair)
                         (list (second pair)
                               (+ (first pair) (second pair))))
                       '(0 1))))
(stream-take 10 fib)
=> '(0 1 1 2 3 5 8 13 21 34)

基于soegaard使用即时推导的想法,这里是一个in-nest-sequence序列生成器(也可以在Code Review和Gist上获得):

#lang racket
(require (for-syntax unstable/syntax))
(provide (rename-out [*in-nest-sequence in-nest-sequence]))
(define in-nest-sequence
  (case-lambda
    [(func init)
     (make-do-sequence
      (thunk (values identity func init #f #f #f)))]
    [(func . inits)
     (make-do-sequence
      (thunk (values (curry apply values)
                     (lambda (args)
                       (call-with-values (thunk (apply func args)) list))
                     inits #f #f #f)))]))
(define-sequence-syntax *in-nest-sequence
  (lambda () #'in-nest-sequence)
  (lambda (stx)
    (syntax-case stx ()
      [[(x ...) (_ func init ...)]
       (unless (= (syntax-length #'(x ...)) (syntax-length #'(init ...)))
         (raise-syntax-error 'in-nest-sequence
                             (format "~a values required" (syntax-length #'(x ...)))
                             stx #'(init ...)))
       (with-syntax ([for-arity (syntax-length #'(init ...))]
                     [(value ...) (generate-temporaries #'(init ...))]
                     [(y ...) (generate-temporaries #'(init ...))])
         #'[(x ...) (:do-in ([(f) func])
                            (unless (procedure-arity-includes? f for-arity)
                              (raise-arity-error f (procedure-arity f) init ...))
                            ([value init] ...)
                            #t
                            ([(x ...) (values value ...)]
                             [(y ...) (f value ...)])
                            #t
                            #t
                            (y ...))])])))

in-nest-sequence生成的序列不会终止,因此您需要将其与具有终止条件的序列或#:break或类似的终止条件配对。例如(使用Óscar回答中的powers-of-two示例):

;; first ten powers of 2
(for/list ((_ (in-range 10))
           (x (in-nest-sequence (curry * 2) 1)))
  x)
; => (1 2 4 8 16 32 64 128 256 512)
;; powers of 2 above 10,000 and below 1,000,000
(for/list ((x (in-nest-sequence (curry * 2) 1))
           #:when (> x 10000)
           #:break (> x 1000000))
  x)
; => (16384 32768 65536 131072 262144 524288)
;; first power of 2 above 10,000,000
(for/first ((x (in-nest-sequence (curry * 2) 1))
            #:when (> x 10000000))
  x)
; => 16777216

下面是斐波那契数列的例子:

;; first ten Fibonacci numbers
(for/list ((_ (in-range 10))
           ((x y) (in-nest-sequence (lambda (a b) (values b (+ a b))) 0 1)))
  x)
; => (0 1 1 2 3 5 8 13 21 34)
;; first Fibonacci number above 10,000,000
(for/first (((x y) (in-nest-sequence (lambda (a b) (values b (+ a b))) 0 1))
            #:when (> x 10000000))
  x)
; => 14930352

最新更新