Haskell如何打印可变向量

3
import           Control.Monad.IO.Class  (liftIO)
import           Control.Monad.Primitive
import qualified Data.Vector             as V
import qualified Data.Vector.Mutable     as MV

fromList :: [a] -> IO (MV.IOVector a)
fromList = V.thaw . V.fromList

printMV :: PrimMonad m => MV.MVector (PrimState m) a -> m ()
printMV = liftIO . print . V.freeze

我想打印出 MVector(惊讶于没有显示实例)。所以我必须先将其冻结为 Vector。然后我得到了类型错误:

Algo/QuickSort.hs:12:11: error: …
    • Couldn't match typePrimState m’ with ‘PrimState m0’
      Expected type: MV.MVector (PrimState m) a -> m ()
        Actual type: MV.MVector (PrimState m0) a -> m ()
      NB: ‘PrimState’ is a non-injective type family
      The type variable ‘m0’ is ambiguousIn the expression: liftIO . print . V.freeze
      In an equation for ‘printMV’: printMV = liftIO . print . V.freeze
    • Relevant bindings include
        printMV :: MV.MVector (PrimState m) a -> m ()
          (bound at /home/skell/btree/Algo/QuickSort.hs:12:1)
   |
Compilation failed.

我也尝试过使用 IOVector

printMV :: MV.IOVector a -> IO ()
printMV = liftIO . print . V.freeze

这次的错误不同:

Algo/QuickSort.hs:12:28: error: …
    • Couldn't match typePrimState m0’ with ‘RealWorld
      Expected type: MV.IOVector a -> m0 (V.Vector a)
        Actual type: MV.MVector (PrimState m0) a -> m0 (V.Vector a)
      The type variable ‘m0’ is ambiguousIn the second argument of ‘(.)’, namely ‘V.freeze’
      In the second argument of ‘(.)’, namely ‘print . V.freeze’
      In the expression: liftIO . print . V.freeze
   |
Compilation failed.

1
不能有一个 Show 实例(或者至少,不是你可能想要的那个 Show 实例),因为 show 不允许执行 IO 操作,而从向量中读取需要 IO - Daniel Wagner
@DanielWagner,你的意思是所有的Haskeller都像我刚才做的那样打印vector吗? - daydaynatation
1
嗯,那个说法可能太绝对了。freeze是肯定可以的一种方式;但还有很多其他的方式。例如,可以在不冻结的情况下迭代索引,或按某些特定算法的顺序呈现元素,使其更易读,或将向量转换为树,因为它实际上是一个线性化堆,或使用向量创建一个单调计算的brick小部件,等等…… - Daniel Wagner
@DanielWagner 你如何迭代一个 MVector?我找不到它的 FoldableTraversable 实例。我能否以某种方式使用 mapM_ print 进行迭代? - daydaynatation
由于与无法有“Show”实例的原因基本相同,也不能有“Foldable”或“Traversable”实例。但是例如,对于基于IO的向量,mapM_(MV.read v> = > print)[0 .. MV.length v-1]可以正常工作,其中MVData.Vector.Mutable。(如果您感到需要速度,则可以使用MV.unsafeRead。高级Haskeller还可以手动编写循环,如果他们不信任列表融合来消除[0 .. MV.length v-1]。但是只有在验证此循环的速度确实重要时才应执行这两个操作 - 在打印时几乎从不发生。) - Daniel Wagner
1个回答

4

有几件事情需要解决 - 第一个解决方案是:

printMV :: MonadIO m => Show a => PrimMonad m => MV.MVector (PrimState m) a -> m ()
printMV v = do
    fv <- V.freeze v
    liftIO $ print fv

问题如下:

  • freeze本身是一个m动作,因此需要绑定
  • liftIO需要一个MonadIO实例
  • 为了使Vector a成为Show类型——a也必须属于这个类

你的第二个版本与此相似:

printMV2 :: Show a => MV.IOVector a -> IO ()
printMV2 v = V.freeze v >>= print
  • 需要 aShow 实例
  • 需要对 V.freeze 的结果进行 >>= 操作 (与上面相同 - do 会自动执行此操作)
  • 这里不需要使用 liftIO,因为已经在其中了

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接