Disk serialization of variables & tables is already part of Arc 3.1's fromdisk, diskvar, disktable, and todisk:
$ arc
Use (quit) to quit, (tl) to return here after an interrupt.
arc> (disktable h "/tmp/nested")
#hash()
arc> (= h (obj this "this" that 3 nested-hash-table (obj one "one" two "two" three 3) some-list (list 1 2 "three" 4)))
#hash((that . 3) (some-list . (1 2 "three" 4 . nil)) (this . "this") (nested-hash-table . #hash((one . "one") (two . "two") (three . 3))))
arc> (todisk h)
((nested-hash-table #hash((one . "one") (two . "two") (three . 3))) (this "this") (some-list (1 2 "three" 4)) (that 3))
arc> (quit)
$ cat /tmp/nested && echo
((nested-hash-table #hash((one . "one") (two . "two") (three . 3))) (this "this") (some-list (1 2 "three" 4)) (that 3))
$ arc
Use (quit) to quit, (tl) to return here after an interrupt.
arc> (disktable nt "/tmp/nested")
#hash((that . 3) (some-list . (1 2 "three" 4)) (this . "this") (nested-hash-table . #hash((one . "one") (two . "two") (three . 3))))
But, as I'm sure you're aware, the error with the above is that the serialized table (returned by todisk) has a literal Scheme #hash object nested inside, and when you read that back in, it's immutable:
So, the actual salient operation here has little to do with immutable tables, but rather "deep copying" them, an operator that vanilla Arc lacks. It only has copy:
(def copy (x . args)
(let x2 (case (type x)
sym x
cons (copylist x) ; (apply (fn args args) x)
string (let new (newstring (len x))
(forlen i x
(= (new i) (x i)))
new)
table (let new (table)
(each (k v) x
(= (new k) v))
new)
(err "Can't copy " x))
(map (fn ((k v)) (= (x2 k) v))
(pair args))
x2))
But we could model a deep-copy off of that:
; (map deep-copy xs) wouldn't work on dotted lists, hence this helper
(def deep-copylist (xs)
(if (no xs)
nil
(atom xs)
(deep-copy xs)
(cons (deep-copy (car xs))
(deep-copylist (cdr xs)))))
(def deep-copy (x . args)
(let x2 (case (type x)
sym x
char x
int x
num x
cons (deep-copylist x)
string (copy x)
table (let new (table)
(each (k v) x
(= (new (deep-copy k)) (deep-copy v)))
new)
(err "Can't deep copy " x))
(map (fn ((k v)) (= (x2 (deep-copy k)) (deep-copy v)))
(pair args))
x2))