什么';s相当于Clojure';球拍中的s迭代函数
今天我在玩Racket,试图根据同一函数的多个应用程序生成一个不确定的数字序列什么';s相当于Clojure';球拍中的s迭代函数,clojure,functional-programming,racket,Clojure,Functional Programming,Racket,今天我在玩Racket,试图根据同一函数的多个应用程序生成一个不确定的数字序列 在Clojure中,我会为此使用迭代函数,但我不确定Racket中的等价物是什么。内置Racket过程中没有直接等价物,但我们可以使用实现类似功能的东西。试试这个: (define (stream-take m s) (if (zero? m) '() (cons (stream-first s) (stream-take (sub1 m) (stream-rest
在Clojure中,我会为此使用迭代函数,但我不确定Racket中的等价物是什么。内置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)
((需要srfi/41)
)直接提供流迭代
您可以使用Ó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)
在大多数情况下,您可以将iterate
替换为for/fold
> (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
基于soegaard使用渴望理解的想法,这里有一个嵌套序列中的
序列生成器(也可提供和使用):
由嵌套序列中的生成的序列不终止,因此您需要将其与终止的序列或:break
或类似终止条件配对。例如(使用Óscar答案中的两个
的幂):
下面是斐波那契序列的例子:
;; 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
另外-期望/fold
比stream更快。当然,热切的理解比streams更轻量级实际上,我应该在iterate序列生成器中编写一个,可以直接与一起用于理解。@ChrisJester-Young这是个好主意。我在iterate
中发布了我的,作为一个新答案。我喜欢它的一点是,它可以处理多个值,而不需要让用户打包和解包(与Óscar的答案和我的初始答案不同)。事实上,我希望有朝一日它能成为Racket标准库的一部分…(我的代码是在“公共领域风格”CC0下发布的,可以自由使用,也可以不使用属性)。我迫不及待地想看看定义序列语法版本:-)看起来很棒,不过我会花一些时间来消化它。我是一个非常挑剔的n00b。@interstar在-*
实现中没有真正容易的方法来消化;它们是使用一种特殊的领域特定语言编写的(无论是我使用的make-do-sequence
,还是soegaard建议的define-sequence-syntax
)。但是如果你喜欢学习新的东西,它肯定会达到这个目的!至于在iterate
中使用,则更容易。对于单参数情况(上面的(curry*2)
示例,顺便说一下,它与(lambda(x)(*2x))
相同),这应该非常简单。双参数案例只是扩展了概念(以及您传入的函数)以使用两个参数和两个返回值。@soegaard我编写了define sequence syntax
版本的第一部分。不过,我在这方面完全不在行,所以我欢迎你的任何批评!(实际上,我应该将此发布到CodeReview Stack Exchange,看看我得到了什么反馈。:/P)
;; 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