Mapping functions

The procedures string-for-each and string-map are documented under Strings.

The procedure string-cursor-for-each is documented under String Cursor API.

Procedure: map proc sequence1 sequence2 ...

Procedure: for-each proc sequence1 sequence2 ...

The map procedure applies proc element-wise to the elements of the sequences and returns a list of the results, in order. The dynamic order in which proc is applied to the elements of the sequences is unspecified.

The for-each procedure does the same, but is executed for the side-effects of proc, whose result (if any) is discarded. Unlike map, for-each is guaranteed to call proc on the elements of the sequencess in order from the first element(s) to the last. The value returned by for-each is the void value.

Each sequence must be a generalized sequence. (Traditionally, these arguments were restricted to lists, but Kawa allows sequences, including vectors, Java arrays, and strings.) If more than one sequence is given and not all sequences have the same length, the procedure terminates when the shortest sequence runs out. The sequences can be infinite (for example circular lists), but it is an error if all of them are infinite.

The proc must be a procedure that accepts as many arguments as there are sequence arguments. It is an error for proc to mutate any of the sequences. In the case of map, proc must return a single value.

(map cadr '((a b) (d e) (g h)))
    ⇒ (b e h)

(map (lambda (n) (expt n n))
     '(1 2 3 4 5))
    ⇒ (1 4 27 256 3125)

(map + ’(1 2 3) ’(4 5 6 7))  ⇒ (5 7 9)

(let ((count 0))
  (map (lambda (ignored)
         (set! count (+ count 1))
         count)
       '(a b)))
    ⇒ (1 2) or (2 1)

The result of map is a list, even if the arguments are non-lists:

(map +
     #(3 4 5)
     (float[] 0.5 1.5))
    ⇒ (3.5 5.5)

To get a vector result, use vector-map.

(let ((v (make-vector 5)))
  (for-each (lambda (i)
              (vector-set! v i (* i i)))
            '(0 1 2 3 4))
  v)
    ⇒  #(0 1 4 9 16)

A string is considered a sequence of character values (not 16-bit char values):

(let ((v (make-vector 10 #\-)))
  (for-each (lambda (i ch)
              (vector-set! v i ch))
            [0 <: ]
            "Smile 😃!")
   v)
    ⇒ #(#\S #\m #\i #\l #\e #\space #\x1f603 #\! #\- #\-)

Performance note: These procedures are pretty well optimized. For each sequence the compiler will by default create an iterator. However, if the type of the sequence is known, the compiler will inline the iteration code.

Procedure: vector-map proc sequence1 sequence2

Same as the map procedure, except the result is a vector. (Traditionally, these arguments were restricted to vectors, but Kawa allows sequences, including lists, Java arrays, and strings.)

(vector-map cadr '#((a b) (d e) (g h)))
    ⇒ #(b e h)

(vector-map (lambda (n) (expt n n))
            '#(1 2 3 4 5))
    ⇒ #(1 4 27 256 3125)

(vector-map + '#(1 2 3) ’#(4 5 6 7))
    ⇒ #(5 7 9)

(let ((count 0))
  (vector-map
    (lambda (ignored)
      (set! count (+ count 1))
      count)
    '#(a b)))
    ⇒ #(1 2) or #(2 1)

Procedure: vector-for-each proc vector1 vector2

Mostly the same as for-each, however the arguments should be generalized vectors. Specifically, they should implement java.util.List (which both regular vectors and uniform vectors do). The vectors should also be efficiently indexable.

(Traditionally, these arguments were restricted to vectors, but Kawa allows sequences, including lists, Java arrays, and strings.)

(let ((v (make-list 5)))
  (vector-for-each
    (lambda (i) (list-set! v i (* i i)))
    '#(0 1 2 3 4))
  v)
    ⇒ (0 1 4 9 16)