badkins
2020-12-3 17:03:55

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


sorawee
2020-12-3 17:13:59

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


badkins
2020-12-3 17:21:07

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


sorawee
2020-12-3 17:26:34

Wait, how can you for/sum when you iterate to infinity?!?


sorawee
2020-12-3 17:26:52

Oh, there’s [line lines]


sorawee
2020-12-3 17:30:06

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


notjack
2020-12-3 17:59:45

What’s wrong with (in-range 0 +inf.0 delta)?


sorawee
2020-12-3 18:10:07

One concern is efficiency


sorawee
2020-12-3 18:10:33

#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


notjack
2020-12-3 18:15:25

that’s just the difference between unbounded and bounded in-range though, not how the unbounded range is written


sorawee
2020-12-3 18:17:06

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?


samth
2020-12-3 18:17:41

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


samth
2020-12-3 18:17:45

which is a fixnum


badkins
2020-12-3 18:28:20

@notjack to answer your question, +inf.0 feels more like a magic number than symbol/keyword to indicate “forever”


notjack
2020-12-3 18:29:44

@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


badkins
2020-12-3 18:29:58

I think I’d prefer that not providing end would indicate there is no end.


notjack
2020-12-3 18:31:02

@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


notjack
2020-12-3 18:31:29

perhaps if it was (in-range start [end +inf.0] #:step [step 1])


badkins
2020-12-3 18:31:53

@notjack are you confusing end with start here?


badkins
2020-12-3 18:32:10

i.e. it’s not possible to not provide end currently


notjack
2020-12-3 18:32:11

possibly, I didn’t sleep much


notjack
2020-12-3 18:33:12

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.


notjack
2020-12-3 18:33:45

(these APIs are so bizarre honestly)


soegaard2
2020-12-3 18:59:57

Why not use in-naturals instead?


badkins
2020-12-3 19:04:28

In this case, I was going for concision, and having to compute x as a function of natural numbers made it too ugly :)


soegaard2
2020-12-3 20:14:55

I forgot it only has a start argument.


hazel
2020-12-4 07:49:41

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


hazel
2020-12-4 07:49:54

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


hazel
2020-12-4 07:50:23

this works initially but macros can’t dereference runtime variables, so it has to be a string literal


hazel
2020-12-4 07:52:23

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


hazel
2020-12-4 07:52:44

(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


hazel
2020-12-4 07:53:15

so what do I do?


hazel
2020-12-4 07:59:31

neeevermind I underestimated the power of ... :stuck_out_tongue:


hazel
2020-12-4 07:59:38

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