Now that you write out the definitions, I see why they work, but I certainly couldn't have come up with them on the fly.  The whole thing kind of reminds me of K idioms, which are like APL idioms, only even harder because K has both ad hoc arity overloading and ad hoc type overloading.  For example, unary ! is iota, binary ! on numbers is modulo, and binary ! on a list and a number is list rotation.)

On Thu, Jul 25, 2019 at 11:34 AM Per Bothner <xxxxxx@bothner.com> wrote:
For what it is worth, one could express

   (array-map + a1 a2)

as:

   (array-copy
    (build-array (array-shape a1)
                 (lambda (I)
                   (+ (array-ref a1 I) (array-ref a2 I))))))

This uses array-copy, which could be defined as:

(define (array-copy arr)
   (array-reshape (array-flatten arr) (array-shape arr)))

Using array-as-procedure and Kawa argument splicing:

   (array-copy
    (build-array (array-shape a1)
                 (lambda (I)
                   (+ (a1 @I) (a2 @I))))))

Using array-as-procedure and Kawa pattern matching:

    (build-array (array-shape a1)
                 (lambda ([i j])
                   (+ (a1 i j) (a2 i j))))))

This is not to argue that array-map doesn't belong in an
arraya API (I think it does), but to show that it is only
a modest reduction in boilerplate.  And using build-array
is obviously more flexible. Performance-wise (and assuming no
non-trivial optimizations) build-array is probably more expensive
than a single array-map, but is probably cheaper than multiple
array-maps.  (You can often use build-array to manually merge
multiple array-maps.)
--
        --Per Bothner
xxxxxx@bothner.com   http://per.bothner.com/