Why does this not generate a matrix in racket?

Viewed 56

I would like to generate a matrix (perhaps with numbers from a process, used 0 for simplification as below) in racket. I tried

(array (for/vector ((x (range 4)))
           (for/vector ((y (range 4)))
             0)))

which gives

(array '#(#(0 0 0 0) #(0 0 0 0) #(0 0 0 0) #(0 0 0 0)))

Silly enough though,

(matrix? (array (for/vector ((x (range 4)))
           (for/vector ((y (range 4)))
             0))))

gives #f, and so does (array '#(#(0 0 0 0) #(0 0 0 0) #(0 0 0 0) #(0 0 0 0))). Yet

> (matrix? (array #(#(0 0 0 0) #(0 0 0 0) #(0 0 0 0) #(0 0 0 0))))
#t

So what's going wrong with it?


EDIT: the matrix module is imported from math/array and math/matrix.

2 Answers

The array special form defines a new syntax, according to the docs it expects "nested rows of expressions" as its argument, which is not the same as a vector. For example:

(require math/array)
(require math/matrix)

(array #[#[1]])
=> (array #[#[1]])
(matrix? (array #[#[1]]))
=> #t

(array (vector (vector 1)))
; notice the difference, there's a quote and the brackets are not square
=> (array '#(#(1)))
(matrix? (array (vector (vector 1))))
=> #f

To summarize: you can't use a vector of vectors as a substitute for the special syntax that array requires as its argument. And it's not just a matter of removing the quote and using square brackets, they're objects of different types even though they look similar when printed.

array is some special magic thing which I don't understand but its body is not a general-purpose expression at all. If you want to make an array programmatically you want something like build-array or vector*->array:

(define nvs (for/vector ((x (range 4)))
              (for/vector ((y (range 4)))
                0)))

(define a (vector*->array nvs number?))
Related