Re: Proposal to reduce the number of argument to array-for-each, array-every, and array-any Bradley Lucier 01 Dec 2025 16:24 UTC

On 11/25/25 04:32, Alex Shinn wrote:
>
> On Tue, Nov 11, 2025 at 8:22 AM Bradley Lucier <xxxxxx@purdue.edu
> <mailto:xxxxxx@purdue.edu>> wrote:
>
>     The old behavior can be obtained with
>
>     (array-for-each (apply array-map f array arrays))
>     (array-every (apply array-map predicate array arrays))
>     (array-any (apply array-map predicate array arrays))
>
>     So a lot more explicit array-map's in code, with the benefit that it's
>     clear that array-for-each, array-every, array-any just evaluate
>     elements
>     of an array in order, with different control-flow semantics.
>
>
> I think this is kind of weird from a user perspective.  Especially when
> used to other collection SRFIs where we generally have:
>
>    (*-for-each f seq0 seq1 ...)
>    (*-every predicate seq0 seq1 ...)
>    (*-any predicate seq0 seq1 ...)

Yes, I agree it is "kind of weird".

I've come to think of generalized arrays ("nonstrict arrays" in Racket's
math/array), stateful procedures that carry their domains around with
them, as weird enough that they don't count as "collection" data
structures like lists, vectors, hash tables, trees, etc.

The documentation for Neil Toronto's math/array library in Racket states
==================
To use nonstrict arrays effectively, think of every array as if it were
the array’s procedure itself. In other words,

     An array is just a function with a finite, rectangular domain.

Some arrays are mutable, some are lazy, some are strict, some are
sparse, and most do not even allocate contiguous space to store their
elements. All are functions that can be applied to indexes to retrieve
elements.

The two most common kinds of operations, mapping over and transforming
arrays, are compositions. Mapping f over array arr is nothing more than
composing f with arr’s procedure [f on the left]. Transforming arr using
g, a function from new indexes to old indexes, is nothing more than
composing arr’s procedure with g [g on the right].
==================
I've added the interpolated phrases [...].

So array-map is unlike the other *-map procedures.  It doesn't
immediately transform a collection of items into another collection of
items.  The fact that the procedure "-map" in its name is misleading (as
I found out from some correspondence with users of the SRFI 231 sample
implementation).

I believe that having array-{for-each|any|every} take only a single
argument may emphasize to users that arrays are different to other
collection data structures.

And perhaps we should rename array-map to array-compose to emphasize its
true nature.
> It's also easier for implementations to fast-path certain cases without
> always requiring an intermediary map.I don't quite understand this.  Outside of error checking, the code in
the sample implementation is the same either way---first compose f or
predicate with the argument arrays' getters and call the associated
interval-<whatever> procedure. (This isn't true for
array-fold-{left|right}, so these procedures still take multiple array
arguments.)

If you don't mind, I'd like to forward this discussion to the Racket
Discourse chat.

Brad