[英]Queues in Racket?
我使用以下代碼來解決Sum by Factors :
#lang racket
(provide sum-of-divided)
(define (sum-of-divided lst)
(define (go ps n l)
(define ((exhaust d) x)
(define q (/ x d))
(if (integer? q)
((exhaust d) q)
(if (> x 1) `(,x) '())))
(if (null? l)
ps
(if
(for/or
([p ps])
#:break (< n (sqr p))
(= 0 (modulo n p)))
(go ps (+ n 1) l)
(go
(append ps `(,n))
(+ n 1)
(append-map (exhaust n) l)))))
(for*/list
([m (go '() 2 (map abs lst))]
[s `(,(for/fold
([a '(0 #f)])
([x lst])
(if (= 0 (modulo x m))
`(,(+ (car a) x) #t)
a)))]
#:when (cadr s))
`(,m ,(car s))))
令我驚訝的是,它通過了時間限制為 12 秒的測試,只有在我sequence-append
L20 中的sequence-append
更改為append
。 sequence-append
的文檔說:
新序列是惰性構建的。
但是,事實證明,這顯然意味着除非需要,否則不會連接后續序列。 但是當需要它們的元素時,即序列sequence-append
產生的sequence-append
被消耗得足夠遠,時間成本與所有先前序列的長度之和成線性關系。 對? 這就是它慢的原因嗎?
如果是這樣,如何解決它? (在這種情況下, append
性能足夠高,但假設我真的需要一個結構,它至少是一個具有通常復雜性的 FIFO 隊列。)在racket
語言中是否有一個很好的替代方案,而不require
額外的包(可能不可用,就像 Codewars 的情況一樣)? 差異列表可能(很容易從頭開始實現)?
我最終使用了明顯的,迄今為止故意避免的:可變列表:
#lang racket
(provide sum-of-divided)
(define (sum-of-divided lst)
(define ps (mcons 0 '()))
(define t ps)
(for*/list
([m
(let go ([n 2] [l (map abs lst)])
(if (null? l)
(mcdr ps)
(go
(+ n 1)
(if
(for/or
([p (mcdr ps)])
#:break (< n (sqr p))
(= 0 (modulo n p)))
l
(begin
(set-mcdr! t (mcons n '()))
(set! t (mcdr t))
(remq*
'(1)
(map
(λ (x)
(let exhaust ([s x])
(define q (/ s n))
(if (integer? q)
(exhaust q)
s)))
l)))))))]
[s `(,(for/fold
([a '(0 #f)])
([x lst])
(if (= 0 (modulo x m))
`(,(+ (car a) x) #t)
a)))]
#:when (cadr s))
`(,m ,(car s))))
我還嘗試了一種使用流的純函數式方法:
#lang racket
(provide sum-of-divided)
(define primes
(letrec
([ps
(stream*
2
(for*/stream
([i (in-naturals 3)]
#:unless
(for/or
([p ps])
#:break (< i (sqr p))
(= 0 (modulo i p))))
i))])
ps))
(define (sum-of-divided lst)
(for/fold
([l lst]
[r '()]
#:result (reverse r))
([d primes])
#:break (null? l)
(values
(remq*
'(1)
(map
(λ (x)
(let exhaust ([s x])
(define q (/ s d))
(if (integer? q)
(exhaust q)
s)))
l))
`(,@(for/fold
([a 0]
[f #f]
#:result
(if f
`((,d ,a))
'()))
([n lst])
(if (= 0 (modulo n d))
(values (+ a n) #t)
(values a f)))
,@r))))
令人驚訝的是,它始終超時,而上面的命令式從未超時。 我相信 Racket 的實現者至少同樣關心功能風格的性能,我很失望。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.