保存并传递先前结果的映射

时间:2011-03-26 12:58:44

标签: haskell map

当在Haskell中通过Tridiagonal matrix algorithm求解线性方程组时,我遇到了以下问题。

我们有三个向量:abc,我们想要制作第三个向量c',它们是它们的组合:

c'[i] = c[i] / b[i], i = 0
c'[i] = c[i] / (b[i] - a[i] * c'[i-1]), 0 < i < n - 1
c'[i] = undefined, i = n - 1

在Haskell中对上述公式的简单实现如下:

calcC' a b c = Data.Vector.generate n f
  where
    n = Data.Vector.length a
    f i = 
      | i == 0 = c!0 / b!0 
      | i == n - 1 = 0
      | otherwise = c!i / (b!i - a!i * f (i - 1))

由于重复,看起来这个函数calcC'具有复杂性 O n 2 )。但我们实际需要的是将一个以前生成的值传递给内部函数f

我编写了自己的generate版本,复杂度为 O n )和帮助函数mapP

mapP f xs = mapP' xs Nothing
  where
    mapP' [] _ = []
    mapP' (x:xs) xp = xn : mapP' xs (Just xn)
      where
        xn = f x xp

generateP n f = Data.Vector.fromList $ mapP f [0 .. n-1]

如您所见,mapP的作用类似于标准map,但也会传递给先前生成的值的映射函数或第一次调用的Nothing

我的问题:在Haskell中有什么漂亮的标准方法吗?我不是要重新发明一点吗?

感谢。

3 个答案:

答案 0 :(得分:10)

有两个名为mapAccumLmapAccumR的标准功能可以完全按照您的需要进行操作。

mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
mapAccumR :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])

基本上,它们的行为类似于foldmap

map   f   = snd . mapAccumL (\_ x -> (()   , f x) ()
foldl f b = fst . mapAccumL (\b x -> (f b x, () ) b

答案 1 :(得分:1)

如果你使用懒惰的Data.Array,你可以通过在定义c'时引用c'直接表示重现。

答案 2 :(得分:1)

在我的情况下,以下代码似乎是上面公式的最简单实现:

import qualified Data.Vector.Generic as V

calcC' a b c = V.postscanl' f 0.0 $ V.zip3 a b c
  where
    f c' (a, b, c) = c / (b - a * c')

感谢Vector的作者添加了有用的postscanl'方法。