[racket] for/hash and for/list: adding nothing, adding more than one thing

From: J. Ian Johnson (ianj at ccs.neu.edu)
Date: Thu Mar 21 19:13:54 EDT 2013

To skip iterations, you want to use the #:when or #:unless for-clauses. In your first example, you should write
(for/list ([i '(1 2 3 4 5)]
           #:when (even? i))
  (* i 100))

Your second wish is less doable in the current state of things. I have a library on github [1] that allows you to extend for/fold with arbitrary accumulation styles, so you can easily write a style that adds several items if there are several (or always several).

To add several elements to an accumulated hash, you have several options to represent the multitude of key/value pairs you wish to add. Let's just say the body of your loop produces a list of key/value pairs.
You would then write (I'm going to give arbitrary keys, since you provided none)

(define-accumulator hash*
 [h #:initial #hash()
    #:bind alst
    #:inner (for/fold ([h h]) ([kv (in-list alst)])
              (hash-set h (car kv) (cdr kv)))])
(for/accumulate ([h #:type hash*]) ([i '(1 2 3 4 5)])
  (list (cons i (* i 100)) (cons (- i) (* i 200))))

[1] https://github.com/ianj/nifty-macros

Disclaimer: this library does not bind defined accumulators so that you can attach accumulator styles to existing bindings. In this case if you want to provide hash*, you should write

(define-syntax (hash* stx) (raise-syntax-error #f "For use in for/accumulate" stx))


----- Original Message -----
From: "Tim Nelson" <tbnelson at gmail.com>
To: "users" <users at racket-lang.org>
Sent: Thursday, March 21, 2013 6:55:35 PM GMT -05:00 US/Canada Eastern
Subject: [racket] for/hash and for/list: adding nothing, adding more than one thing

Dear All, 

I've recently started hacking Racket again, and am loving the for/* constructs. 
Awesome stuff. However, I have two questions about for/hash. 

(1) How can I *not* add a hash entry for a given iteration? 

When I use for/list, can I abuse the nature of empty and append* (I cringe as I write this): 

(append* (for/list ([i '(1 2 3 4 5)]) 
(cond [(even? i) (list (* i 100))] 
[else empty]))) 

Surely there is a better way to do this for for/list, and a way in general for for/hash? 

(2) How can I add multiple entries (that is, >1 key-value pair) in a given iteration? 

Again, using for/list I can cheat via append*: 

(append* (for/list ([i '(1 2 3 4 5)]) 
(list (* i 100) (* i 200)))) 

What's the right way to do this in for/hash? 

- Tim 

  Racket Users list:

Posted on the users mailing list.