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])))
...)))))