(module helper mzscheme
(require (lib "contract.ss")
"reduction-semantics.ss")
(define counter 0)
(define (generate-string)
(set! counter (add1 counter))
(format "s~a" counter))
(define (unique-names? l)
(let ([ht (make-hash-table)])
(andmap (lambda (n)
(if (hash-table-get ht n (lambda () #f))
#f
(begin
(hash-table-put! ht n #t)
#t)))
l)))
(define (all-of P ?)
(let ([l (let loop ([sexp P])
(cond
[(? sexp) (list sexp)]
[(pair? sexp) (append (loop (car sexp)) (loop (cdr sexp)))]
[else null]))]
[ht (make-hash-table)])
(for-each (lambda (i) (hash-table-put! ht i #t)) l)
(hash-table-map ht (lambda (k v) k))))
(define-syntaxes (lang-match-lambda*
lang-match-lambda-memoized*
lang-match-lambda
lang-match-lambda-memoized)
(let ([generic
(lambda (lam)
(lambda (stx)
(syntax-case stx ()
[(_ (id ...) main-id grammar [pattern result] ...)
(with-syntax ([red (generate-temporaries #'(pattern ...))]
[lam lam]
[ids #'(id ...)])
(syntax/loc
stx
(let ([lang grammar]
[escape (make-parameter void)])
(let ([reds (list (reduction grammar pattern ((escape) (lambda ids result)))
...)])
(lam (id ...)
((let/ec esc
(parameterize ([escape esc])
(reduce reds main-id)
(error 'lang-match-lambda "no pattern matched input: ~e" main-id)))
id ...))))))])))]
[single
(lambda (multi)
(lambda (stx)
(syntax-case stx ()
[(_ (id) grammar [pattern result] ...)
(with-syntax ([multi multi])
#'(multi (id) id grammar [pattern result] ...))])))])
(values
(generic #'lambda)
(generic #'lambda-memoized)
(single #'lang-match-lambda*)
(single #'lang-match-lambda-memoized*))))
(define (transitive-closure orig)
(let ([map (map (lambda (p) (list (car p) (cdr p))) orig)])
(let loop ()
(let ([changed? #f])
(for-each (lambda (pair)
(let ([mapping (cdr pair)])
(for-each (lambda (item)
(let ([trans (ormap (lambda (transitive)
(and (not (memq transitive mapping))
transitive))
(cdr (assq item map)))])
(when trans
(append! pair (list trans))
(set! changed? #t))))
mapping)))
map)
(when changed? (loop))))
map))
(define-syntax (lambda-memoized stx)
(syntax-case stx ()
[(_ () body1 body ...)
(syntax/loc stx (lambda () body1 body ...))]
[(_ (arg) body1 body ...)
(syntax/loc
stx
(let ([ht (make-hash-table 'weak)])
(lambda (arg)
(hash-table-get
ht
arg
(lambda ()
(let ([v (begin body1 body ...)])
(hash-table-put! ht arg v)
v))))))]
[(_ (arg1 arg ...) body1 body ...)
(syntax/loc
stx
(let ([memo (lambda-memoized (arg1) (lambda-memoized (arg ...) body1 body ...))])
(lambda (arg1 arg ...)
((memo arg1) arg ...))))]))
(define-syntax define-memoized
(syntax-rules ()
[(_ (f . args) body1 body ...)
(define f (lambda-memoized args body1 body ...))]))
(define (function-reduce* reds expr done? max-steps)
(cons
expr
(if (or (zero? max-steps) (done? expr))
null
(let ([l (reduce reds expr)])
(cond
[(null? l) null]
[(= 1 (length l))
(function-reduce* reds (car l) done? (sub1 max-steps))]
[else
(error 'function-reduce*
"found ~a possible steps from ~e"
(length l)
expr)])))))
(define-struct multi-result (choices))
(define-syntax (explore-results stx)
(syntax-case stx ()
[(_ (id) result-expr body-expr bes ...)
#'(let ([try (lambda (id) body-expr bes ...)])
(let ([r result-expr])
(do-explore r try)))]))
(define-syntax (explore-parallel-results stx)
(syntax-case stx ()
[(_ (list-id) result-list-expr body-expr bes ...)
#'(let ([try (lambda (list-id) body-expr bes ...)])
(let loop ([rs result-list-expr][es null])
(if (null? rs)
(try (reverse es))
(do-explore
(car rs)
(lambda (e)
(loop (cdr rs) (cons e es)))))))]))
(define (do-explore r try)
(cond
[(multi-result? r)
(let loop ([l (multi-result-choices r)])
(if (null? l)
#f
(let ([a ((car l))])
(if (multi-result? a)
(loop (append (multi-result-choices a)
(cdr l)))
(let ([v (try a)])
(if (not v)
(loop (cdr l))
(make-multi-result
(append (if (multi-result? v)
(multi-result-choices v)
(list (lambda () v)))
(list (lambda () (loop (cdr l))))))))))))]
[else (try r)]))
(define (many-results l)
(make-multi-result (map (lambda (v) (lambda () v)) l)))
(define (first-result result)
(let/ec k
(explore-results (x) result
(k x))))
(provide
define-memoized
lambda-memoized
lang-match-lambda
lang-match-lambda-memoized
lang-match-lambda*
lang-match-lambda-memoized*
explore-results
explore-parallel-results)
(provide/contract
(function-reduce* ((listof red?) any/c (any/c . -> . boolean?) number?
. -> . (listof any/c)))
(unique-names? ((listof symbol?) . -> . boolean?))
(generate-string (-> string?))
(all-of (any/c (any/c . -> . any) . -> . (listof any/c)))
(transitive-closure ((listof pair?) . -> . (listof (listof any/c))))
(many-results ((listof (lambda (x) (not (multi-result? x)))) . -> . any))
(first-result (any/c . -> . any))))