matrix.ss
#lang scheme
(require (planet jaymccarthy/spvector))

(define-struct matrix (rows cols cells)
  #:transparent)

(define (build-matrix rs cs f)
  (make-matrix
   rs cs
   (build-spvector
    rs
    (lambda (r)
      (build-spvector
       cs
       (lambda (c)
         (f r c)))))))

(define (validate-ref f m r c)
  (cond
    [(r . >= . (matrix-rows m))
     (error f "no row ~a" r)]
    [(c . >= . (matrix-cols m))
     (error f "no column ~a" c)]))

(define (matrix-valid-ref? m r c)
  (with-handlers ([exn? (lambda _ #f)])
    (validate-ref 'valid-ref? m r c)
    #t))

(define (matrix-ref m r c)
  (validate-ref 'matrix-ref m r c)
  (spvector-ref (spvector-ref (matrix-cells m) r) c))

(define (matrix-set m vr vc v)
  (validate-ref 'matrix-set m vr vc)
  (make-matrix (matrix-rows m)
               (matrix-cols m)
               (spvector-set (matrix-cells m) vr
                             (spvector-set (spvector-ref (matrix-cells m) vr) vc v))))

(define (matrix-set! m vr vc v)
  (validate-ref 'matrix-set! m vr vc)
  (spvector-set! (spvector-ref (matrix-cells m) vr) vc v))

(define (matrix-fold m row-f col-f a)
  (for/fold ([a a])
    ([r (matrix-cells m)]
     [ri (in-range 0 (matrix-rows m))])
    (row-f
     ri
     (for/fold ([a a])
       ([v r]
        [ci (in-range 0 (matrix-cols m))])
       (col-f ri ci v a)))))

(define (display-matrix m)
  (for ([ri (in-range 0 (matrix-rows m))])
    (for ([ci (in-range 0 (matrix-cols m))])
      (display (matrix-ref m ri ci)))
    (unless (= ri (sub1 (matrix-rows m)))
      (newline))))

(provide/contract
 [matrix-rows (matrix? . -> . exact-positive-integer?)]
 [matrix-cols (matrix? . -> . exact-positive-integer?)]
 [matrix? (any/c . -> . boolean?)]
 [build-matrix
  (exact-positive-integer?
   exact-positive-integer?
   (exact-nonnegative-integer? exact-nonnegative-integer? . -> . any/c)
   . -> .
   matrix?)]
 [matrix-valid-ref? (matrix? exact-nonnegative-integer? exact-nonnegative-integer? . -> . boolean?)]
 [matrix-ref (matrix? exact-nonnegative-integer? exact-nonnegative-integer? . -> . any/c)]
 [matrix-set (matrix? exact-nonnegative-integer? exact-nonnegative-integer? any/c . -> . matrix?)]
 [matrix-set! (matrix? exact-nonnegative-integer? exact-nonnegative-integer? any/c . -> . void)]
 [matrix-fold (matrix? 
               (exact-nonnegative-integer? any/c . -> . any/c)
               (exact-nonnegative-integer? exact-nonnegative-integer? any/c any/c . -> . any/c)
               any/c . -> . any/c)]
 [display-matrix (matrix? . -> . void)])