有没有办法在Haskell中“保留”结果?

时间:2015-08-25 13:09:43

标签: haskell functional-programming memoization

我是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,其中缺少此功能会导致糟糕的表现。

1 个答案:

答案 0 :(得分:12)

使用合适的库,例如MemoTrie

import Data.MemoTrie

f' = memo f
 where f 0 = ... 
       f n = f' ...

这几乎不比Mathematica版本好,是吗?

关于

  

“为什么不能简单地(实际上)将评估的函数重新定义为它们的计算值?”

嗯,总的来说不是那么容易。这些值必须存储在某处。即使对于Int值函数,也不能只分配具有所有可能值的数组 - 它不适合内存。列表解决方案只能起作用,因为Haskell是惰性的,因此允许无限列表,但这并不是特别令人满意,因为查找是 O n )。 对于其他类型,它只是毫无希望 - 你需要以某种方式对一个过度无数的无限域进行对角化。

你需要一些更聪明的组织。我不知道Mathematica是如何做到这一点的,但它可能会使用很多“专有魔法”。对于任何输入,我都不会确定它确实以您喜欢的方式工作。

幸运的是,Haskell有类型类,这些类允许您准确表达类型需要什么才能快速记忆。 HasTrie就是这样一个类。