Haskell 哈斯克尔的部分回忆录

Haskell 哈斯克尔的部分回忆录,haskell,ghc,memoization,Haskell,Ghc,Memoization,我正试图找到一种好方法,使用Data.MemoCombinators,在Haskell中只记忆函数的一部分域(非负整数) import Data.MemoCombinators --approach 1 partFib n | n < 0 = undefined | otherwise = integral fib n where fib 0 = 1 fib 1 = 1 fib k = partFib (k-1) + partFib (k-2) --a

我正试图找到一种好方法,使用
Data.MemoCombinators
,在Haskell中只记忆函数的一部分域(非负整数)

import Data.MemoCombinators

--approach 1

partFib n | n < 0 = undefined
          | otherwise = integral fib n where
  fib 0 = 1
  fib 1 = 1
  fib k = partFib (k-1) + partFib (k-2)

--approach 2

partFib2 n | n < 0 = undefined
           | otherwise = fib n
fib = integral fib'
  where
    fib' 0 = 1
    fib' 1 = 1
    fib' n = partFib2 (n-1) + partFib2 (n-2)
import Data.memos
--方法1
partFib n | n<0=未定义
|否则=积分fib n,其中
fib 0=1
fib 1=1
fibk=partFib(k-1)+partFib(k-2)
--方法2
partFib2 n | n<0=未定义
|否则=fib n
fib=积分fib'
哪里
fib'0=1
fib'1=1
fib'n=partFib2(n-1)+partFib2(n-2)
方法1是我想怎么做的,但是,它似乎不起作用。我认为这是因为每次调用
partFib
时,
fib
函数都被“重新创建”,从而丢弃了记忆
fib
不依赖于
partFib
的输入,因此您可以假设编译器可以提升它,但显然GHC不是这样工作的

方法2是我最终如何做到这一点。Eerk,很多丑陋的线路

有人知道更好的方法吗?

不太清楚什么是你眼中的“丑陋”,但你可以通过将记忆操作从
n
的功能中取消,在只使用一个顶级标识符的情况下进行正确的记忆

partFib3 = \n -> if n < 0 then undefined else fib' n
    where fib 0 = 1
          fib 1 = 1
          fib k = partFib3 (k-1) + partFib3 (k-2)
          fib' = integral fib
partFib3=\n->如果n<0,则未定义else fib'n
其中fib 0=1
fib 1=1
fibk=partFib3(k-1)+partFib3(k-2)
fib'=积分fib

嗯,把东西分开一点怎么样:

fib 0 = 0
fib 1 = 1
fib x = doFib (x-1) + doFib (x-2)

memFib = Memo.integral fib

doFib n | n < 0 = fib n
        | otherwise memFib n
fib 0=0
fib 1=1
fibx=doFib(x-1)+doFib(x-2)
memFib=Memo.integral fib
doFib n | n<0=fib n
|否则memFib n

现在您需要使用doFib。

库中有一个用于此目的的组合器:

开关p a b
p
为真时使用备忘表
a
,在
p
为假时使用备忘表
b

回想一下,
id
在技术上是一个回忆录器(它不回忆录:-),因此您可以执行以下操作:

partFib = Memo.switch (< 0) id Memo.integral fib'
    where
    ...
partFib=Memo.switch(<0)id Memo.integral fib'
哪里
...

谢谢,这比我的好。没有什么是真正的“丑陋”,我只是想让定义看起来尽可能类似于天真的斐波那契实现。为什么这会有不同?在语义上是否与
f=\n->e
完全相同?@Dan,在语义上,是的。但备忘录正在进入操作领域。前者中的
n
的作用域是
where
子句,而后者中的
n
的作用域不是,因此改变了where子句中thunk的共享方式。@Dan,最近这篇关于共享变量绑定的文章有更详细的内容:Richard Bird与Haskell的功能性思考的第7章也是关于这个主题的一篇很好的阅读。谢谢。我也喜欢这个。它将函数定义与记忆内容的定义清晰地分开。所谓“记忆器(不记忆:-)”,您的意思是它的类型是
Memo a
,因此类型系统允许您将其用作记忆器?
partFib = Memo.switch (< 0) id Memo.integral fib'
    where
    ...