我今天正在玩Racket,并试图基于同一函数的多个应用程序生成一个不确定的数字序列。
在Clojure中,我会使用迭代函数来实现这一点,但我不确定在Racket中等效的是什么。
SRFI 41 ((require srfi/41)
)直接提供stream-iterate
您可以使用Óscar的示例并在看到iterate
的地方替换stream-iterate
,而不必定义自己的iterate
。此外,您可以使用match-lambda
:
(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)
返回两个值:256
和1/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