I am C/C++ programmer and I started learning Racket / reading SICP. I have a question about effective representation of matrices in functional programming.
// up to N random cells initialized with random values
// matrix is a current state of the game field
for (n = 0; n < Random(N); n++)
{
matrix[Random(X)][Random(Y)] = Random(MAX);
}
This code is simple and effective. How to write this code effective in functional style for a large immutable matrix? Is it possible? If yes, then how?
Thank you very much for your answer!
As Óscar said, the most traditional functional programming approach would be to use linked lists. However, a more direct (albeit with some mutation) approach would be to use vectors.
However, since you mentioned you were doing this in Racket, you can actually use for/vector
to make your matrix. You can either either use a vector of vectors, as in:
(define my-matrix
(for/vector ([i (in-range 3)])
(for/vector ([j (in-range 3)])
(random))))
which makes a 3x3 vector of random numbers. Now you can use vector-ref
twice to get an element out of it.
;; Evaluates to the middle most cell in the matrix
(vector-ref (vector-ref my-matrix 1) 1)
Another approach you can do is to take a C-like approach, and use a single vector for the whole matrix. This requires you to store an extra argument for the width of course, but can make things a bit cleaner.1 For example, you could make a 3x3 matrix that contains the numbers 1 through 9:
(define matrix-width 3)
(define matrix
(for/vector ([i (in-range 1 10)])
i))
And now you only need a single vector-ref
to get your element:
;; This also gets the middle most cell.
(vector-ref matrix (+ 1 (* 1 matrix-width)) ; => 5
Of course, if you want to do this a lot, it make sense to wrap this into a single data-structure:
(struct matrix (width data))
(define (make-matrix width height)
(make-vector (* width height)))
(define (matrix-ref m i j)
(vector-ref (matrix-data m) (+ i (* j (matrix-width m)))))
(define (matrix-set! m i j v)
(vector-set! (matrix-data m) (+ i (* j (matrix-width m))) v))
Of course, you could go even further, and with a little more work and a small macro and you can even add for/matrix
and in-matrix
as looping constructs, as well as matrix math library. But at some point you will have effectively made the math/matrix
library which comes with typed racket.2
1Of course this is purely subjective, and will also depend on your program.
2Technically it also works with standard, untyped, Racket, but much slower.