Is there a better way to do (in-range 0 +inf.0 delta) ? In particular, using +inf.0 didn’t feel right. Maybe if the args were reordered & end was optional? (define (in-my-range start step [end +inf.0])
(in-range start end step))
Personally, I’d just write a let-loop if you want to iterate indefinitely. The main advantage (to me) of for + in-range over let-loop is that I don’t need to test for termination explicitly, but when you iterate indefinitely, you don’t need the test anyway.
(let loop ([n start])
(println n)
(loop (+ n 3)))
I do typically lean toward (let loop ..., but in this case, I was looking for something more concise and for seemed like a good fit: ;; loop version
(define (count-loop lines x delta)
(let loop ([ lines lines ][ x x ][ count 0 ])
(if (null? lines)
count
(loop (cdr lines) (+ x delta) (if (and (exact-integer? x)
(char=? #\# (mod-ref (car lines) x)))
(add1 count)
count)))))
;; for version
(define (count-for lines x delta)
(for/sum ([ line lines ]
[ x (in-range 0 +inf.0 delta) ])
(if (and (exact-integer? x) (char=? #\# (mod-ref line x))) 1 0)))
Wait, how can you for/sum when you iterate to infinity?!?
Oh, there’s [line lines]
One alternative (which might not be better):
(for/fold ([x 0] [sum-so-far 0] #:result sum-so-far)
([line lines])
(values (+ x delta) (+ sum-so-far (if ...))))
What’s wrong with (in-range 0 +inf.0 delta)?
One concern is efficiency
#lang racket
(define xs (build-list 1000000 values))
(time
(for/sum ([x (in-list xs)] [n (in-range 1000000)])
1))
; cpu time: 21 real time: 24 gc time: 14
(time
(for/sum ([x (in-list xs)] [n (in-range +inf.0)])
1))
; cpu time: 82 real time: 97 gc time: 70
that’s just the difference between unbounded and bounded in-range though, not how the unbounded range is written
I’m not sure if I understand your response.
Do you consider
(time
(for/fold ([sum 0]) ([x (in-list xs)])
(+ sum 1)))
; cpu time: 3 real time: 3 gc time: 0 unbounded?
it would be very clever if we could figure out how to optimize the latter like the former, since you can actually tell that the bound is the length of the list
which is a fixnum
@notjack to answer your question, +inf.0 feels more like a magic number than symbol/keyword to indicate “forever”
@sorawee I mean that the in-my-range form that @badkins suggested still creates an unbounded range, it just does so without the user typing +inf.0
I think I’d prefer that not providing end would indicate there is no end.
@badkins not providing end does indicate that there is no end…. unfortunately there’s no way to provide step without providing end, and if you flip the argument order then there’s no way to provide end without providing step and honestly neither of those options seems great
perhaps if it was (in-range start [end +inf.0] #:step [step 1])
@notjack are you confusing end with start here?
i.e. it’s not possible to not provide end currently
possibly, I didn’t sleep much
oh right, the one-argument case does that weird thing where it assumes start is zero. I’m getting things mixed up between in-range and in-naturals.
(these APIs are so bizarre honestly)
Why not use in-naturals instead?
In this case, I was going for concision, and having to compute x as a function of natural numbers made it too ugly :)
I forgot it only has a start argument.
I’m trying to create a means to which I can update a struct field (like struct-copy) except it takes a /string/ field name
my initial instinct was: (define-simple-macro (struct-insert strct:id name:id fld:str val:expr)
#:with fld-name (format-id #'fld "~a" (syntax-e #'fld))
(struct-copy strct name
[fld-name val]))
this works initially but macros can’t dereference runtime variables, so it has to be a string literal
so my next idea was to create a hash table binding field names of the given struct to lambdas that update the given field and do that with a macro
(define-simple-macro (struct+ name:id fld:id ...+)
#:with hash-name (format-id #'name "~a-insert-table" #'name)
(begin (struct name (fld ...) #:transparent)
(define hash-name (make-hash))
(for ([fd (in-list '(fld ...))])
(hash-set! hash-name fd
(lambda (strct val)
(struct-copy name strct
[fd val])))))) this doesn’t work because fd is a runtime variable and I run into the same issue that I was in before
so what do I do?
neeevermind I underestimated the power of ... :stuck_out_tongue:
(define-simple-macro (struct+ name:id fld:id ...+)
#:with hash-name (format-id #'name "~a-insert-table" #'name)
(begin (struct name (fld ...) #:transparent)
(define hash-name
(make-hasheq (list (cons 'fld
(lambda (strct val)
(struct-copy name strct
[fld val])))
...)))))