Frage

I'm really interested in becoming proficient in Clojure/Clojurescript for web applications. Right now I'm making simple command-line applications to get a feel for the language.

But right now it's hard to grasp the workflow of how to get things done in a language without mutable variables.

My problem is: I'm making a little RPN Calculator, in which the user can enter numbers to add to a stack and also do math operations on the stack:

> ;adding to stack
> 4 4
> ; print the stack
> [4, 4]
> 2 3
> p
> [4 4 2 3]
> ; adding the top two items to the stack
> +
> p
> [4 4 5]
> + -
> p
> [-5]

So my problem is how to keep track of the stack, if there are no variables. I wrote this in Java first using the Java stack, and obviously in Clojure it's going to be a much different approach, but I'm not quite sure the way to approach the problem.

War es hilfreich?

Lösung

While it works, I'd avoid the atom/ref approach, as these are not really the "Clojure way". (They are the correct tools for some problems, but not this one). The stack-frame approach is much more in line with Clojure philosophy.

To expand on the stack-frame solution, the application of each operation would be a function like:

new-stack (apply-op stack op)

Operations like + and - will do the obvious, while 'p' will have a side-effect (IO) but otherwise return the original stack.

The loop is then trivial:

(loop [stack [] op (get-op!)]
    (if (not= 'q op)
        (recur (apply-op stack op) (get-op!))))

I'm presuming a symbol of 'q' as the termination command, and get-op! to be the reading operation.

Also worth noting is that the "stack" is more naturally implemented with a list, as the required operations of first/rest/cons are already available. For instance, applying any binary operator to a list-based stack is just:

(cons (the-operator (first stack) (second stack)) (rest (rest stack)))

Or using destructuring for clarity:

(let [[a b & r] stack] (cons (the-operator a b) r))

Using a vector as a stack is not so easy, nor efficient.

Andere Tipps

You can either structure it, in a way that is similar to Java, with an atom, or ref, to keep track of the current stack or restructure the problem as a recursive loop that "stores" the current stack within the callstack. The latter solution could use a lot of stack frames, so you would want to use recur to prevent a stack overflow.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top