#lang racket

(provide model)

(struct variable ((value #:mutable) rule))

(define-syntax make-store
  (syntax-rules ()
    ((_ _make-store_ _get-value_ ((_type_ _id_ _args_ ...) ...))
     (let-syntax
         ((make-entry
           (syntax-rules (? =)
             ((_ (? __id__  __init-value__) __other-ids__)
	      `(__id__ . ,(variable __init-value__ #f)))
	     ((_ (= __id__ __rule__) (__other-id__ (... ...)))
              `(__id__
		.
		,(variable
		  #f
		  (lambda ()
		    (let-syntax
			((__other-id__
			  (syntax-id-rules ()
			    (_ (_get-value_ '__other-id__))))
			 (... ...))
		      __rule__))))))))
       (letrec
	   ((store
	     (_make-store_
	      `(,(make-entry (_type_ _id_ _args_ ...) (_id_ ...)) ...)) ))
	 store)))))

(define-syntax model
  (syntax-rules ()
    ((_ _make-store_ _store-ref_ ((_type_ _id_ _args_ ...) ...))
     (let ()
       (define (get-variable id) (_store-ref_ store id))
       (define (get-value id) (variable-value (get-variable id)))
       (define store (make-store _make-store_ get-value ((_type_ _id_ _args_ ...) ...)))

       (match-lambda*
	((list 'get id) (get-value id)))
       ))))