(define (pop stack)
 (let ((var (car stack))
               (ret-stack (cdr stack)))
       (values var ret-stack)))

(define (push var stack)
 (append (list var) stack))

(define (dup stack)
 (let ((head (car stack)))
       (append (list head) stack)))

(define (fact x)
 (define (fact-iter n current)
       (if (= n 1)
         current
         (fact-iter (- n 1) (* n current))))
 (fact-iter x 1))

(define (rpn-func func stack)
 (let*-values (((var1 stack) (pop stack))
                               ((var2 stack) (pop stack)))
       (push (func var1 var2) stack)))

(let loop ((input (read)) (stack '()))
 (cond
  ((number? input) (loop (read) (push input stack)))
  ((eq? '+ input) (loop (read) (rpn-func + stack)))
  ((eq? '- input) (loop (read) (rpn-func - stack)))
  ((eq? '* input) (loop (read) (rpn-func * stack)))
  ((eq? '/ input) (loop (read) (rpn-func / stack)))
  ((eq? '% input) (loop (read) (rpn-func modulo stack)))
  ((eq? '! input) (loop (read)
                                                (let-values (((var stack) (pop stack)))
                                                  (push (fact var) stack))))
  ((eq? '$ input) (loop (read)
                                                (let-values (((var stack) (pop stack)))
                                                  (display var)
                                                  (newline)
                                                  stack)))
  ((eq? 'dup input) (loop (read) (dup stack)))
  (else (begin
                  (display "ERROR not valid input: ")
                  (display input)
                  (newline)
                  (loop (read) stack)))))