chickadee » srfi-179 » array-reverse

array-reverse array #!optional flip?procedure

We assume that array is an array and flip?, if given, is a vector of booleans whose length is the same as the dimension of array. If flip? is not given, it is set to a vector with length the same as the dimension of array, all of whose elements are #t.

array-reverse returns a new array that is specialized, mutable, or immutable according to whether array is specialized, mutable, or immutable, respectively. Informally, if (vector-ref flip? k) is true, then the ordering of multi-indices in the k'th coordinate direction is reversed, and is left undisturbed otherwise.

More formally, we introduce the function

(define flip-multi-index
  (let* ((domain (array-domain array))
         (lowers (interval-lower-bounds->list domain))
         (uppers (interval-upper-bounds->list domain)))
    (lambda (multi-index)
      (map (lambda (i_k flip?_k l_k u_k)
             (if flip?_k
                 (- (+ l_k u_k -1) i_k)
                 i_k))
           multi-index
           (vector->list flip?)
           lowers
           uppers))))

Then if array is specialized, array-reverse returns

(specialized-array-share
 array
 domain
 (lambda multi-index
   (apply values
          (flip-multi-index multi-index))))

and the result inherits the safety and mutability of array.

Otherwise, if array is mutable, then array-reverse returns

(make-array
 domain
 (lambda multi-index
   (apply (array-getter array)
          (flip-multi-index multi-index)))
   (lambda (v . multi-index)
     (apply (array-setter array)
            v
            (flip-multi-index multi-index)))))

Finally, if array is immutable, then array-reverse returns

(make-array
 domain
 (lambda multi-index
   (apply (array-getter array)
          (flip-multi-index multi-index))))) 

It is an error if array and flip? don't satisfy these requirements.

The following example using array-reverse was motivated by a blog post by Joe Marshall.

(define (palindrome? s)
  (let ((n (string-length s)))
    (or (< n 2)
        (let* ((a
                ;; an array accessing the characters of s
                (make-array (make-interval (vector n))
                            (lambda (i)
                              (string-ref s i))))
               (ra
                ;; the array accessed in reverse order
                (array-reverse a))
               (half-domain
                (make-interval (vector (quotient n 2)))))
          (array-every
           char=?
           ;; the first half of s
           (array-extract a half-domain)
           ;; the reversed second half of s
           (array-extract ra half-domain))))))

(palindrome? "") => #t
(palindrome? "a") => #t
(palindrome? "aa") => #t
(palindrome? "ab") => #f
(palindrome? "aba") => #t
(palindrome? "abc") => #f
(palindrome? "abba") => #t
(palindrome? "abca") => #f
(palindrome? "abbc") => #f