# Stack calculator in Racket

I have implemented a stack calculator based on this programming task. I wondered if a more experienced racketeer could give me feedback and tell me if I am missing anything in Racket that would enable the solution to be more elegant.

#lang racket

(define (inc n)
(+ n 1))

(define (print-value s)
(begin
(display s)
(display " ")))

(define (exec l (stack empty) (opcount 1))
"executes a stack based program."
(cond
[(empty? l) (void)]

;; push number onto stack
[(number? (string->number (first l)))
(exec (rest l)
(cons (string->number (first l)) stack)
(inc opcount))]

;; pop number from stack
[(equal? (first l) ".")
(begin
(print-value (first stack))
(exec (rest l) (rest stack)
(inc opcount)))]

;; mathmatical operators
[(equal? (first l) "+")
(exec (rest l) (cons
(+ (first stack) (second stack))
(rest (rest stack))) (inc opcount))]
[(equal? (first l) "-")
(exec (rest l) (cons
(- (first stack) (second stack))
(rest (rest stack))) (inc opcount))]
[(equal? (first l) "*")
(exec (rest l) (cons
(* (first stack) (second stack))
(rest (rest stack))) (inc opcount))]
[(equal? (first l) "/")
(exec (rest l) (cons
(/ (first stack) (second stack))
(rest (rest stack))) (inc opcount))]

;; duplication operator
[(equal? (string-downcase (first l)) "dup")
(exec (rest l)
(cons (first stack) stack) (inc opcount))]
[else
(~a "Error: operation " opcount " invalid")]))

(define program (string-split "64 DUP * ."))

(exec program)

• (Welcome to CR!) (Do you know Rosetta?) – greybeard Feb 18 '18 at 18:59
• Cond clauses have an implicit begin, and support any arbitrary number us secondary clauses, executed in the order they appear. This the begin in the "." operator case is unneeded. – WorBlux May 28 '18 at 15:53

## Bug

The - and / operators interpret their operands backwards from the typical RPN order. That is, I expect "10 7 -" should produce 3, but it actually produces -3.

## Recursion

Your code is awfully repetitive, because the handler for each operator has to fetch the operator ((first l)), perform the operation, then make the recursive call ((exec (rest l) … (inc opcount))). It would be worthwhile to define a helper function that applies the operator to the stack.

(define (apply-op op stack)
(cond
[(number? (string->number op))
(cons (string->number op) stack)]
[(equal? op ".")
(begin
(display (first stack))
(display " ")
(rest stack))]
[(equal? op "+")
(cons (+ (second stack) (first stack)) (rest (rest stack)))]
[(equal? op "-")
(cons (- (second stack) (first stack)) (rest (rest stack)))]
[(equal? op "*")
(cons (* (second stack) (first stack)) (rest (rest stack)))]
[(equal? op "/")
(cons (/ (second stack) (first stack)) (rest (rest stack)))]
[(equal? (string-downcase op) "dup")
(cons (first stack) stack)]
[else
(~a "operation '" op "' invalid")]))


Then, the exec function just has to call it and drive the recursion.

(define (exec ops (stack empty) (opcount 1))
"executes a stack based program."
(cond
[(empty? ops) (void)]
[else
(let ([next-stack (apply-op (first ops) stack)])
(if (string? next-stack)
(~a "Error at operator " opcount ": " next-stack)
(exec (rest ops) next-stack (+ opcount 1))))]))