main.rkt
#lang racket
#|  _    ____  ___   ______________________  _   _____    __ 
   | |  / / / / / | / / ____/_  __/  _/ __ \/ | / /   |  / / 
   | | / / / / /  |/ / /     / /  / // / / /  |/ / /| | / /  
   | |/ / /_/ / /|  / /___  / / _/ // /_/ / /|  / ___ |/ /___
   |___/\____/_/ |_/\____/ /_/ /___/\____/_/ |_/_/  |_/_____/
       ____________________________  ____  _____
      / ____/ ____/ ____/_  __/ __ \/ __ \/ ___/
     / /_  / __/ / /     / / / / / / /_/ /\__ \ 
    / __/ / /___/ /___  / / / /_/ / _, _/___/ / 
   /_/   /_____/\____/ /_/  \____/_/ |_|/____/               
   Persistent Functional Vectors.

   Copyright (c) 2011 David Van Horn
   Licensed under the Academic Free License version 3.0
  
   (at dvanhorn (dot ccs neu edu))

   Vucking vast vunctional fectors.
|#

(provide fector? make-fector fector fector-length 
         build-fector fector-ref fector-set)

;; An [Fector X] is a (fox [Data X])
;; A [Data X] is one of:
;; - [Vector X]
;; - (diff Nat X [Fector X])

;; Based on Conchon and Filliaˆtre, ML Workshop 2007,
;; which is based on Baker, CACM 1978.

;; Like a box, but different.
(struct fox (v) 
        #:mutable
        #:property prop:equal+hash
        (list
         (λ (f1 f2 equal?)
           (reroot! f1)
           (reroot! f2)
           (equal? (unfox f1) (unfox f2)))
         (λ (f equal-hash-code)
           (reroot! f)
           (equal-hash-code (unfox f)))
         (λ (f equal-hash-code)
           (reroot! f)
           (equal-hash-code (unfox f)))))           
        
(define (set-fox! fb x) (set-fox-v! fb x))
(define (unfox fb) (fox-v fb))

(struct diff (i v fv))

(define (fector? x) (fox? x))

(define (make-fector n x)
  (fox (make-vector n x)))

(define (fector . xs)
  (fox (apply vector xs)))

(define (fector-length fv)
  (reroot! fv)
  (vector-length (unfox fv)))

(define (build-fector n f)
  (fox (build-vector n f)))

(define (fector-ref fv i)
  (match (unfox fv)
    [(diff _ _ _)
     (reroot! fv)
     (vector-ref (unfox fv) i)]
    [v (vector-ref v i)]))

(define (fector-set fv i x)
  (reroot! fv)
  (let ((v (unfox fv)))
    (let ((old (vector-ref v i)))
      (vector-set! v i x)
      (let ((res (fox v)))
        (set-fox! fv (diff i old res))
        res))))

(define (reroot! fv)
  (match (unfox fv)
    [(diff i x fv*)
     (reroot! fv*)
     (let ((v (unfox fv*)))
       (let ((x* (vector-ref v i)))
         (vector-set! v i x)
         (set-fox! fv v)
         (set-fox! fv* (diff i x* fv))))]
    [v (void)]))

#|
(define a0 (make-fector 7 0))
(define a1 (fector-set a0 1 7))
(define a2 (fector-set a1 2 8))
(define a3 (fector-set a1 2 9))
    
(for/list ([i (in-range 7)])
  (fector-ref a0 i))
(for/list ([i (in-range 7)])
  (fector-ref a1 i))
(for/list ([i (in-range 7)])
  (fector-ref a2 i))
(for/list ([i (in-range 7)])
  (fector-ref a3 i))

(equal? (fox (vector 1 2 3))
        (fox (diff 0 1 (fox (vector 7 2 3)))))
|#