0

我真的很想精通用于 Web 应用程序的 Clojure/Clojurescript。现在我正在制作简单的命令行应用程序来感受这种语言。

但是现在很难掌握如何在没有可变变量的语言中完成工作的工作流程。

我的问题是:我正在制作一个小的RPN计算器,用户可以在其中输入数字以添加到堆栈中,还可以对堆栈进行数学运算:

> ;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]

所以我的问题是如果没有变量,如何跟踪堆栈。我首先使用 Java 堆栈在 Java 中编写了这个,显然在 Clojure 中这将是一种非常不同的方法,但我不太确定解决问题的方法。

4

2 回答 2

1

您可以以类似于 Java 的方式构造它,使用atomref来跟踪当前堆栈,或者将问题重新构造为递归循环,将当前堆栈“存储”在调用堆栈中。后一种解决方案可能会使用大量堆栈帧,因此您可能希望使用它recur来防止堆栈溢出。

于 2013-10-03T04:16:55.140 回答
1

虽然它有效,但我会避免使用 atom/ref 方法,因为这些并不是真正的“Clojure 方式”。(它们解决某些问题的正确工具,但不是这个)。堆栈框架方法更符合 Clojure 哲学。

为了扩展堆栈框架解决方案,每个操作的应用程序将是一个函数,例如:

new-stack (apply-op stack op)

像 + 和 - 这样的操作会很明显,而 'p' 会产生副作用 (IO) 但否则会返回原始堆栈。

然后循环是微不足道的:

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

我假设'q'的符号作为终止命令,并且get-op!成为读操作。

另外值得注意的是,“堆栈”更自然地用列表实现,因为 first/rest/cons 所需的操作已经可用。例如,将任何二元运算符应用于基于列表的堆栈只是:

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

或者为了清楚起见使用解构:

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

将向量用作堆栈并不那么容易,也没有那么高效。

于 2013-10-03T17:26:58.903 回答