;; FIXME: Steps are pairs of Configurations ;; Configurations contain contexts, definites, etc. (module reductions-engine mzscheme (require (lib "list.ss") "deriv.ss" "stx-util.ss" "steps.ss") (require (lib "contract.ss")) (provide (all-from "steps.ss")) (provide context big-context current-derivation current-definites learn-definites current-frontier add-frontier blaze-frontier rename-frontier with-context with-derivation with-new-local-context RSunit RSzero RSbind RSadd RSseq RSforeach RS-steps CC R revappend) (provide walk walk/foci walk/mono stumble stumble/E) ;; context: parameter of Context (define context (make-parameter null)) ;; big-context: parameter of BigContext (define big-context (make-parameter null)) ;; current-derivation : parameter of Derivation (define current-derivation (make-parameter #f)) ;; current-definites : parameter of (list-of identifier) (define current-definites (make-parameter null)) ;; current-frontier : parameter of (list-of syntax) (define current-frontier (make-parameter null)) (define-syntax with-context (syntax-rules () [(with-context f . body) (let ([c (context)]) (parameterize ([context (cons f c)]) (let () . body)))])) (define-syntax with-derivation (syntax-rules () [(with-derivation d . body) (parameterize ((current-derivation d)) . body)])) (define-syntax with-new-local-context (syntax-rules () [(with-new-local-context e . body) (parameterize ([big-context (cons (make-bigframe (current-derivation) (context) (list e) e) (big-context))] [context null]) . body)])) (define (learn-definites ids) (current-definites (append ids (current-definites)))) (define (get-frontier) (or (current-frontier) null)) (define (add-frontier stxs) (current-frontier (let ([frontier0 (current-frontier)]) (and frontier0 (append stxs frontier0))))) (define (blaze-frontier stx) (current-frontier (let ([frontier0 (current-frontier)]) (and frontier0 (remq stx frontier0))))) ;; ----------------------------------- ;; RS: The "reductions monad" ;; (RS a) = (values ReductionSequence ?a ?exn) ;; Not a proper monad, because of 'values' (define-syntax ->RS/c (syntax-rules () [(->RS/c domain-c ...) (-> domain-c ... (values (listof protostep?) any/c (or/c exn? false/c)))])) (define/contract RSzero (->RS/c) (lambda () (values null #f #f))) (define/contract RSunit (->RS/c any/c) (lambda (v) (values null v #f))) (define/contract RSbind (->RS/c (->RS/c) (->RS/c any/c)) (lambda (a f) (let-values ([(rseq1 final1 exn1) (a)]) (if (not exn1) (let-values ([(rseq2 final2 exn2) (f final1)]) (values (append rseq1 rseq2) final2 exn2)) (values rseq1 final1 exn1))))) (define/contract RSseq (->RS/c (->RS/c) (->RS/c)) (lambda (a b) (RSbind a (lambda (_) (b))))) (define/contract RSforeach (->RS/c (->RS/c any/c) (listof any/c)) (lambda (f xs) (let loop ([xs xs]) (if (pair? xs) (RSseq (lambda () (f (car xs))) (lambda () (loop (cdr xs)))) (RSunit (void)))))) (define/contract RSadd (->RS/c (listof protostep?) (->RS/c)) (lambda (steps a) (let-values ([(rseq1 final1 exn1) (a)]) (values (append steps rseq1) final1 exn1)))) (define-syntax RS-steps (syntax-rules () [(RS-steps expr) (let-values ([(rseq final exn) expr]) rseq)])) ;; CC ;; the context constructor (define-syntax (CC stx) (syntax-case stx () [(CC HOLE expr pattern) #'(syntax-copier HOLE expr pattern)])) ;; (R stx R-clause ...) ;; An R-clause is one of ;; [! expr] ;; [#:pattern pattern] ;; [#:bind pattern stx-expr] ;; [#:let-values (var ...) expr] ;; [#:set-syntax stx-expr] ;; [#:walk term2 foci1 foci2 description] ;; [#:walk term2 description] ;; [#:rename form2 foci1 foci2 description] ;; [#:rename/no-step pattern stx stx] ;; [#:reductions expr] ;; [#:learn ids] ;; [#:frontier stxs] ;; [#:when test R-clause ...] ;; [#:if/np test R-clause ...] ;; [generator hole fill] ;; R ;; the threaded reductions engine ;; (R form . clauses) : (values (list-of Step) ?stx ?exn) (define-syntax R (syntax-rules () [(R form . clauses) (R** #f _ [#:set-syntax form] . clauses)])) (define-syntax R** (syntax-rules (! =>) ;; Base: done [(R** form-var pattern) (RSunit form-var)] ;; Base: explicit continuation [(R** f p => k) (k f)] ;; Error-point case [(R** f p [! maybe-exn] . more) (let ([x maybe-exn]) (unless (or (not x) (exn? x)) (raise-type-error 'R "exception" x)) (if x (values (list (stumble f x)) #f x) (R** f p . more)))] ;; Change patterns [(R** f p [#:pattern p2] . more) (R** f p2 . more)] ;; Bind pattern variables [(R** f p [#:bind pattern rhs] . more) (with-syntax ([pattern (with-syntax ([p f]) rhs)]) (R** f p . more))] ;; Bind variables [(R** f p [#:let-values (var ...) rhs] . more) (let-values ([(var ...) (with-syntax ([p f]) rhs)]) (R** f p . more))] ;; Change syntax [(R** f p [#:set-syntax form] . more) (let ([form-variable form]) (R** form-variable p . more))] ;; Change syntax and Step (explicit foci) [(R** f p [#:walk form2 foci1 foci2 description] . more) (let-values ([(form2-var foci1-var foci2-var description-var) (with-syntax ([p f]) (values form2 foci1 foci2 description))]) (RSadd (list (walk/foci foci1-var foci2-var f form2-var description-var)) (lambda () (R** form2-var p . more))))] ;; Change syntax and Step (infer foci) [(R** f p [#:walk form2 description] . more) (let-values ([(form2-var description-var) (with-syntax ([p f]) (values form2 description))]) (RSadd (list (walk f form2-var description-var)) (lambda () (R** form2-var p . more))))] ;; Change syntax with rename [(R** f p [#:rename form2 foci1 foci2 description] . more) (let-values ([(form2-var foci1-var foci2-var description-var) (with-syntax ([p f]) (values form2 foci1 foci2 description))]) (rename-frontier f form2-var) (with-context (make-renames foci1-var foci2-var) (RSadd (list (walk/foci foci1-var foci2-var f form2-var description-var)) (lambda () (R** form2-var p . more)))))] ;; Change syntax with rename (but no step) [(R** f p [#:rename/no-step pvar from to] . more) (let-values ([(from-var to-var) (with-syntax ([p f]) (values from to))]) (let ([f2 (with-syntax ([p f]) (with-syntax ([pvar to]) (syntax p)))]) (rename-frontier from-var to-var) (with-context (make-renames from-var to-var) (R** f2 p . more))))] ;; Add in arbitrary other steps [(R** f p [#:reductions steps] . more) (RSseq (lambda () steps) (lambda () (R** f p . more)))] ;; Add to definites [(R** f p [#:learn ids] . more) (begin (learn-definites (with-syntax ([p f]) ids)) (R** f p . more))] ;; Add to frontier [(R** f p [#:frontier stxs] . more) (begin (add-frontier (with-syntax ([p f]) stxs)) (R** f p . more))] ;; Conditional (pattern changes lost afterwards ...) [(R** f p [#:if/np test [consequent ...] [alternate ...]] . more) (let ([continue (lambda (f2) (R** f2 p . more))]) (if (with-syntax ([p f]) test) (R** f p consequent ... => continue) (R** f p alternate ... => continue)))] ;; Conditional (pattern changes lost afterwards ...) [(R** f p [#:when/np test consequent ...] . more) (let ([continue (lambda (f2) (R** f2 p . more))]) (if (with-syntax ([p f]) test) (R** f p consequent ... => continue) (continue f)))] ;; Conditional [(R** f p [#:when test consequent ...] . more) (if (with-syntax ([p f]) test) (R** f p consequent ... . more) (R** f p . more))] ;; Subterm handling [(R** f p [generator hole fill] . more) (let ([k (lambda (f2) (R** f2 p . more))]) (Run f p generator hole fill k))])) (define-syntax Run (syntax-rules () [(Run f p generator hole fill k) (let ([reducer (with-syntax ([p f]) (generator))]) (Run* reducer f p hole fill k))])) (define-syntax (Run* stx) (syntax-case stx () ;; Implementation of subterm handling for (hole ...) sequences [(Run* f form-var pattern (hole :::) fills k) (and (identifier? #':::) (module-identifier=? #'::: (quote-syntax ...))) #'(let ([ctx (CC (hole :::) form-var pattern)]) (let ([e1s (with-syntax ([pattern form-var]) (syntax->list #'(hole :::)))]) (run-multiple f ctx fills e1s k)))] ;; Implementation of subterm handling [(Run* f form-var pattern hole fill k) #'(let ([ctx (CC hole form-var pattern)]) (run-one f ctx fill k))])) ;; run-multiple : (a -> RS(b)) ((list-of b) -> c) (list-of a) (list-of b) (c -> RS(d)) ;; -> RS(d) ;; For example: a = Deriv; b = c = d = Syntax (define (run-multiple f ctx fills suffix k) (let loop ([fills fills] [prefix null] [suffix suffix]) (cond [(pair? fills) (RSbind (lambda () (with-context ctx (with-context (lambda (x) (revappend prefix (cons x (cdr suffix)))) (f (car fills))))) (lambda (final) (loop (cdr fills) (cons final prefix) (cdr suffix))))] [(null? fills) (let ([form (ctx (reverse prefix))]) (k form))]))) ;; run-one : (a -> RS(b)) (b -> c) (c -> RS(d)) -> RS(d) (define (run-one f ctx fill k) (RSbind (lambda () (with-context ctx (f fill))) (lambda (final) (k (ctx final))))) ;; Rename mapping (define (rename-frontier from to) (current-frontier (with-handlers ([exn:fail? (lambda _ #f)]) (apply append (map (make-rename-mapping from to) (current-frontier)))))) (define (make-rename-mapping from0 to0) (define table (make-hash-table)) (let loop ([from from0] [to to0]) (cond [(syntax? from) (hash-table-put! table from (flatten-syntaxes to)) (loop (syntax-e from) to)] [(syntax? to) (loop from (syntax-e to))] [(pair? from) #;(unless (pair? to) (fprintf (current-error-port) "from:\n~s\n\n" (syntax-object->datum from0)) (fprintf (current-error-port) "to:\n~s\n\n" (syntax-object->datum to0)) (error 'frontier-renaming)) (loop (car from) (car to)) (loop (cdr from) (cdr to))] [(vector? from) (loop (vector->list from) (vector->list to))] [(box? from) (loop (unbox from) (unbox to))] [else (void)])) (lambda (stx) (let ([replacement (hash-table-get table stx #f)]) (if replacement (begin #;(printf " replacing ~s with ~s~n" stx replacement) replacement) (begin #;(printf " not replacing ~s~n" stx) (list stx)))))) (define (flatten-syntaxes x) (cond [(syntax? x) (list x)] [(pair? x) (append (flatten-syntaxes (car x)) (flatten-syntaxes (cdr x)))] [(vector? x) (flatten-syntaxes (vector->list x))] [(box? x) (flatten-syntaxes (unbox x))] [else null])) ;; ----------------------------------- ;; walk : syntax(es) syntax(es) StepType -> Reduction ;; Lifts a local step into a term step. (define (walk e1 e2 type) (make-step (current-derivation) (big-context) type (context) (current-definites) (get-frontier) (foci e1) (foci e2) e1 e2)) ;; walk/foci : syntaxes syntaxes syntax syntax StepType -> Reduction (define (walk/foci foci1 foci2 Ee1 Ee2 type) (make-step (current-derivation) (big-context) type (context) (current-definites) (get-frontier) (foci foci1) (foci foci2) Ee1 Ee2)) ;; walk/mono : syntax StepType -> Reduction (define (walk/mono e1 type) (make-mono (current-derivation) (big-context) type (context) (current-definites) (get-frontier) (foci e1) e1)) ;; stumble : syntax exception -> Reduction (define (stumble stx exn) (make-misstep (current-derivation) (big-context) 'error (context) (current-definites) (get-frontier) (foci stx) stx exn)) ;; stumble/E : syntax(s) syntax exn -> Reduction (define (stumble/E focus Ee1 exn) (make-misstep (current-derivation) (big-context) 'error (context) (current-definites) (get-frontier) (foci focus) Ee1 exn)) ;; ------------------------------------ (define (revappend a b) (cond [(pair? a) (revappend (cdr a) (cons (car a) b))] [(null? a) b])) (define (foci x) (if (list? x) x (list x))) )