#lang scheme/base
(provide
state-lambda update
state-update
stack
stack-list
stack-cons
stack-uncons
stack-top
stack-lambda
make-state:stack
state:stack
)
(require
scheme/match
scheme/stxparam
(for-syntax
scheme/base))
(define-struct state (update))
(define-syntax-parameter update
(lambda (stx)
(raise-syntax-error #f "can only be used inside `state-lambda'" stx)))
(define-syntax state-lambda
(syntax-rules ()
((_ state-type (var ...) . expr)
(lambda (state)
(match state
((struct state-type (update-fn var ...))
(let ((_update
(lambda args
(apply update-fn state args))))
(syntax-parameterize
((update (make-rename-transformer #'_update)))
. expr))))))))
(define-struct (stack state) (list))
(define (make-state:stack l)
(let ((update (lambda (state lst) (make-state:stack lst))))
(make-stack update l)))
(define (state:stack)
(make-state:stack '()))
(define (stack-cons a s)
((state-lambda stack (l)
(update (cons a l)))
s))
(define stack-uncons
(state-lambda stack
(stack)
(unless (pair? stack)
(error 'stack-underflow))
(values
(car stack)
(update (cdr stack)))))
(define-syntax stack-lambda
(syntax-rules ()
((_ formals . body)
(state-lambda stack
(stack)
(update
(apply (lambda formals . body) stack))))))
(define (stack-top s)
(let-values
(((top rest) (stack-uncons s)))
top))