Data.Vector,与累加器映射

时间:2015-03-07 11:47:38

标签: haskell

我想在Data.Vector上用累加器做一张地图。

我想编写函数inc:

inc :: Vector.Vector Bool -> Vector.Vector Bool

向载体“添加一个”,例如:

inc <False, False, False> = <False, False, True>
inc <False, False, True> = <False, True, False>
inc <True, True, True> = <False, False, False>

如果有类似Data.List的mapAccumR,请输入类型:

mapAccumR :: (acc -> x -> (acc, y)) -> acc -> Vector x -> (acc, Vector y)

这可以用

完成
inc = snd . Vector.mapAccumR inc' True
  where
    inc' x y = (x && y, (x || y) && (not (x && y)))

但是我无法弄明白如何使用Data.Vector.Unboxed中的内容来完成它。有可能吗?

1 个答案:

答案 0 :(得分:2)

最简单的解决方案是反转你的方案,并在向量的前面有最低有效位,如下所示:

inc <False, False, False> == <True, False, False>

原因是mapMunfoldr都适合用这个位排序来定义inc,但不适用于其他顺序,并且没有相反的版本vector中的这些功能。例如,mapM允许我们在State monad的帮助下实现inc

import Control.Monad.State
import qualified Data.Vector.Unboxed as V

inc :: V.Vector Bool -> V.Vector Bool
inc v = evalState (V.mapM go v) True where
  go acc = state $ \x -> (x /= acc, x && acc)

或者,我们可以进行两次反转以恢复原始顺序。这将渐近相同,但实际上明显更慢。

当然,我们仍然可以为mapAccumR执行较低级别的实施。这需要在ST monad中使用可变向量进行工作,这不是特别困难,但它也不是微不足道的。 ST monad上没有很多在线资料;在Stack Overflow上你可以benefit from reading this question并可选择跟随那里的链接。我尝试评论下面mapAccumR实施中的重要部分。

-- we need this so we can annotate objects in the ST monad with
-- the right parameters
{-# LANGUAGE ScopedTypeVariables #-}

import Control.Monad.ST.Strict
import qualified Data.Vector.Unboxed as V
import qualified Data.Vector.Unboxed.Mutable as MV

-- note that I explicitly introduce the type variables
-- with forall. This - in conjunction with ScopedTypeVariables - 
-- lets us refer to the type variables in the function body.
mapAccumR ::
  forall x y acc.
  (V.Unbox x, V.Unbox y) =>
  (acc -> x -> (acc, y)) -> acc -> V.Vector x -> (acc, V.Vector y)
mapAccumR f acc v = runST $ do
  let len = V.length v

  -- Allocate a mutable unboxed vector of v's size.
  -- We need to annotate the "s" parameter here, so we can
  -- refer to it in the type of "go".
  (mv :: MV.STVector s y) <- MV.unsafeNew len

  -- iterate through the new vector in reverse order,
  -- updating the elements according to mapAccumR's logic.
  let go :: Int -> acc -> ST s acc
      go i acc | i < 0 = return acc
      go i acc = do
        -- y comes from the old vector
        -- we can access it via the immutable API
        let (acc' , y) = f acc (V.unsafeIndex v i)
        -- but we must do mutable writes on the new vector
        MV.unsafeWrite mv i y
        go (i - 1) acc'

  acc' <- go (len - 1) acc

  -- "unsafeFreeze" converts the mutable vector to
  -- an immutable one in-place.
  v'   <- V.unsafeFreeze mv
  return (acc', v')