我是Haskell的新手并且理解它(基本上)是一种纯函数式语言,其优点是函数的结果不会在多次评估中发生变化。鉴于此,我很困惑,为什么我不能轻易地标记一个函数,以便记住它的第一次评估的结果,并且不需要在每次需要它时再次评估它。
例如,在Mathematica中,有一个simple idiom用于完成此操作:
f[x_]:=f[x]= ...
但是在Haskell中,我发现的最接近的事情是something like
f' = (map f [0 ..] !!)
where f 0 = ...
f n = f' ...
除了不那么明确(并且显然仅限于Int
个参数?)之外(似乎)不会在交互式会话中保留结果。
不可否认(而且很清楚),我不明白到底发生了什么;但天真的是,似乎Haskel在函数定义级别应该有某种方式
有没有办法在Haskell中实现这一点,我错过了?我理解(某种程度上)Haskell不能将评估存储为“状态”,但为什么不能简单地(实际上)将评估函数重新定义为它们的计算值?
这来自this question,其中缺少此功能会导致糟糕的表现。
答案 0 :(得分:12)
使用合适的库,例如MemoTrie。
import Data.MemoTrie
f' = memo f
where f 0 = ...
f n = f' ...
这几乎不比Mathematica版本好,是吗?
关于
“为什么不能简单地(实际上)将评估的函数重新定义为它们的计算值?”
嗯,总的来说不是那么容易。这些值必须存储在某处。即使对于Int
值函数,也不能只分配具有所有可能值的数组 - 它不适合内存。列表解决方案只能起作用,因为Haskell是惰性的,因此允许无限列表,但这并不是特别令人满意,因为查找是 O ( n )。
对于其他类型,它只是毫无希望 - 你需要以某种方式对一个过度无数的无限域进行对角化。
你需要一些更聪明的组织。我不知道Mathematica是如何做到这一点的,但它可能会使用很多“专有魔法”。对于任何输入,我都不会确定它确实以您喜欢的方式工作。
幸运的是,Haskell有类型类,这些类允许您准确表达类型需要什么才能快速记忆。 HasTrie就是这样一个类。