;; Graph/hypertext storage structure for web applications. ;; * Each node contains a series of tags which point to other objects ;; (another node, a data terminal, a closure, ...). ;; * Data accessed from a node is automatically instantiated using ;; 'force-dynamic', which means it can contain dynamic or lazy ;; structures. ;; * Directory-structure access: from each node it is possible to ;; access objects at multiple hop distance, as long as the ;; intermediate objects addressed are nodes. ;; This is to implement: ;; * late binding ;; * lazyness / caching ;; * prototype based programming ;; * ad-hoc graph structured documents #lang scheme/base (begin (require (lib "match.ss") "dynamic.ss") (provide n! n@ p! p@ node? node-map dict->node (rename-out (make-node-initialized make-node)) node-copy n-push! ) (define (n-push! n path value) (let ((stack (n@ n path))) (n! n path (cons value stack)))) (define-struct node (table)) (define (node-copy n) (make-node (hash-copy (node-table n)))) (define (make-node-initialized) (make-node (make-hash))) (define (node-map n fn) (hash-map (node-table n) fn)) (define (on-table proc n args) (apply proc (cons (node-table n) args))) (define (n! n . args) (on-table hash-set! n args)) (define (n@ n . args) (force-dynamic (on-table hash-ref n args))) (define (failed f) (match f (() #f) ((fn/val) (if (procedure? fn/val) (fn/val) fn/val)))) (define (p@ node path . f) (let next ((n node) (p path)) (if (not (node? n)) (failed f) (match path (() n) ((tag . rest) (next (n@ n tag) rest)))))) (define (p! node path thing . f) (let next ((n node) (p path)) (if (not (node? n)) (failed f) (match p ((tag) (n! n tag thing)) ((tag . rest) (next (n@ n tag) rest)))))) (define (p? node path) (and (node? node) (match path (() #t) ((tag . rest) (p? (n@ node tag) rest))))) ;; UTILITY (define (dict->node dict) (define (dict+=hash hash dict) (for-each (lambda (entry) (hash-set! hash (car entry) (cdr entry))) dict) hash) (make-node (dict+=hash (make-hash) dict))) ; (define node+= dict+=hash) )