memoization与无状态代码

时间:2016-02-24 15:31:45

标签: clojure functional-programming clojurescript

在开发无状态Clojure库时遇到了一个问题:必须使用相同的参数重复调用许多函数。由于到目前为止所有内容都没有副作用,因此总会产生相同的结果。我正在考虑如何使这更具表现力。

我的库的工作原理如下:每次调用一个函数时,都需要传递一个state-hash-map,该函数返回一个带有操作状态对象的替换。因此,这可以保持一切不可变,并且每种状态都保持在库之外。

(require '[mylib.core :as l])
(def state1 (l/init-state))
(def state2 (l/proceed state1))
(def state3 (l/proceed state2))

如果继续不应重复执行相同的操作,我有几个选项可以解决这个问题:

选项1:“手工完成”

将必要的状态存储在state-hash-map中,并仅在必要时进行更新。意思是:有一个复杂的机制,知道哪些部分必须重新计算,哪些部分不重新计算。这总是可行的,在我的情况下,这不是那么微不足道。如果我实现了这个,我会生成更多的代码,最终更容易出错。那有必要吗?

选项2:记忆

因此,有一种诱惑是在lib中的关键点使用memoize函数:在这些点上,我期望使用相同的args重复函数调用的可能性。这是另一种编程哲学:将每个步骤建模,就好像它是第一次运行一样。并将多次调用的事实分离到另一个实现。 (这让我想起了反应/ om /试剂的渲染功能)

选项3:core.memoize

但是备忘录是有状态的 - 当然。当lib在web服务器中运行时,这 - 例如 - 成为一个问题。服务器将继续使用捕获的结果填充内存。但就我而言,仅捕获每个用户会话的计算结果是有意义的。因此,将缓存附加到先前描述的状态哈希映射是完美的,它将由lib传回。

看起来core.memoize为这项工作提供了一些工具。不幸的是,它没有得到很好的记录 - 我真的没有找到与所述情况相关的有用信息。

我的问题是:我是否或多或少地正确估计了可能的选项?还是有其他选择我还没有考虑过?如果没有,看起来像core.memoize是要走的路。然后,如果有人可以给我一个简短的模式,我会很感激,这应该在这里使用。

1 个答案:

答案 0 :(得分:1)

如果state1state2& state3在您的示例中有所不同,备忘录将不会为您带来任何好处。每次都会使用不同的参数调用proceed

作为一般设计原则不要对消费者强加缓存策略。设计使你的图书馆的消费者有可能使用任何记忆技术,或根本没有记忆。

此外,您没有提及init-state是否有副作用,以及它是否返回相同的state1。如果是这样,为什么不将所有(或某些)状态保持为静态文字。如果它们不占用太多空间,您可以编写一个计算它们编译时间的宏。比如说,前20个州是硬编码的,然后拨打proceed