Haskell 哈斯克尔:回忆录

Haskell 哈斯克尔:回忆录,haskell,recursion,memoization,Haskell,Recursion,Memoization,我试图重新学习哈斯凯尔,在离开多年后,我忘记了一切,我发现自己仍然对我的记忆感到困惑。特别是,我正试图编写一个程序来生成D[n]对象的混乱数量n对象(原始位置没有项目的排列);数字D[n]可以通过D[1]=0,D[2]=1,D[n]=(n-1)(D[n-1]+D[n-2])递归定义 所以这是可行的: der :: Int -> Integer der n = lder !! n where lder = 1 : 0 : zipWith3 (\n d1 d2 -> n * (d1+

我试图重新学习哈斯凯尔,在离开多年后,我忘记了一切,我发现自己仍然对我的记忆感到困惑。特别是,我正试图编写一个程序来生成
D[n]
对象的混乱数量
n
对象(原始位置没有项目的排列);数字
D[n]
可以通过
D[1]=0
D[2]=1
D[n]=(n-1)(D[n-1]+D[n-2])递归定义

所以这是可行的:

der :: Int -> Integer
der n = lder !! n
  where lder = 1 : 0 : zipWith3 (\n d1 d2 -> n * (d1+d2)) [1..] lder (tail lder)
与此类似(这有点笨拙,因为它需要三个功能):

您会发现最后一个是标准记忆斐波那契数函数的副本。我的函数可以工作,但没有被记忆,因为它挂起的值大于30。此外,如果我将此函数编写为仅对大于或等于1的值进行操作:

nders :: Int -> Integer
nders n = (map der [1 ..]) !! n
  where der 1 = 0
        der 2 = 1
        der n = (nders (n-2) + nders (n-1)) * toInteger (n-1)
这根本不起作用。我很想知道最后两个函数有什么问题。

nders :: Int -> Integer
nders n = (map der [0 ..]) !! n
  where der 0 = 1
        der 1 = 0
        der n = (nders (n-2) + nders (n-1)) * toInteger (n-1)
映射der[0..]
部分将针对
NDS
的任何应用程序重新计算,特别是包括
der
中的递归调用

您可以移出表格的定义,这样它就不会(从语法上)依赖于
n
,这应该是正确的:

nders :: Int -> Integer
nders = (memoized !!)
  where 
    memoized = map der [0 ..]

    der 0 = 1
    der 1 = 0
    der n = (nders (n-2) + nders (n-1)) * toInteger (n-1)

这是一个范围问题。请尝试使用
nds=(map der[0..!!)
,这表示计算
map
时不需要知道
n
(编译器不自动执行此操作的原因是它可能会创建不需要的内存泄漏..这就是您在这里所做的,只是您想要内存泄漏;-)非常感谢!是的,这很好用。这些都是我还没有弄清楚的棘手问题。奇怪的是,地图需要在
[0..]
上定义;如果我在
[1..]
上定义它,函数就不起作用了。是的,那是因为
以零为基础。该策略取决于以下事实:
[0..]!!n=n
对于我们感兴趣的所有
n
s(因为我们需要
map f[0..!!n=fn
,所以它最好适用于
f=id
nders :: Int -> Integer
nders n = (map der [0 ..]) !! n
  where der 0 = 1
        der 1 = 0
        der n = (nders (n-2) + nders (n-1)) * toInteger (n-1)
nders :: Int -> Integer
nders = (memoized !!)
  where 
    memoized = map der [0 ..]

    der 0 = 1
    der 1 = 0
    der n = (nders (n-2) + nders (n-1)) * toInteger (n-1)