简体   繁体   English

如何解冻、变异然后重新冻结 Haskell 向量?

[英]How do I thaw, mutate, then refreeze a Haskell Vector?

I'm working through a tutorial on Haskell Vectors that, as an exercise, asks you to reimplement Data.Vector.Unboxed.modify using runST and "functions introduced earlier in the tutorial" which I take to be thaw & freeze .我正在阅读有关 Haskell 向量的教程,作为练习,要求您使用Data.Vector.Unboxed.modify和“教程前面介绍的函数”重新实现thaw ,我认为它是runST & freeze

This is what I've tried:这是我尝试过的:

#!/usr/bin/env stack
-- stack --resolver lts-12.21 script
import qualified Data.Vector.Unboxed as V
import qualified Data.Vector.Unboxed.Mutable as VM
-- import Data.Vector.Unboxed (modify)
import Control.Monad.ST

-- TODO: debug this...
modify :: VM.Unbox a => (VM.MVector s a -> ST s ()) -> V.Vector a -> V.Vector a
modify sa v = runST $ do
  mv <- V.thaw v
  sa mv
  V.freeze mv

main :: IO ()
main = do
  let vec = V.enumFromTo 1 10 :: V.Vector Int
  print $ modify (\v -> fmap (\_-> ()) $ VM.nextPermutation v) vec

Which gets compile error:哪个得到编译错误:

$ ./modify.hs
./modify.hs:11:9: error:                                                                                            
    • Couldn't match type ‘s1’ with ‘s’                                                                                                                        
      ‘s1’ is a rigid type variable bound by                                                                                                                   
        a type expected by the context:                                                                                                                        
          forall s1. ST s1 (V.Vector a)                                                                                                                        
        at /home/tom/code/fpco-haskell-tutorials/vector/modify.hs:(10,15)-(13,13)                                                                              
      ‘s’ is a rigid type variable bound by                                                                                                                    
        the type signature for:                                                                                                                                
          modify :: forall a s.                                                                                                                                
                    VM.Unbox a =>                                                                                                                              
                    (VM.MVector s a -> ST s ()) -> V.Vector a -> V.Vector a                                                                                    
        at /home/tom/code/fpco-haskell-tutorials/vector/modify.hs:9:1-79
      Expected type: ST s1 (VM.MVector s a)                                               
        Actual type: ST                        
                       s1                    
                       (VM.MVector
                          (primitive-0.6.3.0:Control.Monad.Primitive.PrimState (ST s1)) a)
    • In a stmt of a 'do' block: mv <- V.thaw v
      In the second argument of ‘($)’, namely
        ‘do mv <- V.thaw v
            _ <- sa mv       
            V.freeze mv’ 
      In the expression:  
        runST                  
          $ do mv <- V.thaw v          
               _ <- sa mv                                                       
               V.freeze mv                                               
    • Relevant bindings include                                                 
        sa :: VM.MVector s a -> ST s ()
          (bound at /home/tom/code/fpco-haskell-tutorials/vector/modify.hs:10:8)
        modify :: (VM.MVector s a -> ST s ()) -> V.Vector a -> V.Vector a
          (bound at /home/tom/code/fpco-haskell-tutorials/vector/modify.hs:10:1)
   |
11 |   mv <- V.thaw v                                              
   | 

I think the important bit is:我认为重要的一点是:

      Expected type: ST s1 (VM.MVector s a)                                               
        Actual type: ST                        
                       s1                    
                       (VM.MVector
                          (primitive-0.6.3.0:Control.Monad.Primitive.PrimState (ST s1)) a)

Looking at my attempt at modify :看看我的modify尝试:

modify :: VM.Unbox a => (VM.MVector s a -> ST s ()) -> V.Vector a -> V.Vector a
modify sa v = runST $ do
  mv <- V.thaw v
  sa mv
  V.freeze mv

What I'm trying to express is:我想表达的是:

  • Thaw the Vector into a MVectorVector解冻为MVector
  • Perform the mutation执行突变
  • Freeze into a new Vector冻结成一个新的Vector

If I comment out where I try to perform the mutation:如果我注释掉我尝试执行突变的位置:

modify sa v = runST $ do
  mv <- V.thaw v
  -- sa mv
  V.freeze mv

the code compiles and runs to produce an unmodified vector.代码编译并运行以生成未修改的向量。

$ ./modify.hs 
[1,2,3,4,5,6,7,8,9,10]

So there's something wrong with the way I'm trying to apply the stateful action sa to modify the mutable vector mv .因此,我尝试应用有状态操作sa来修改可变向量mv的方式有问题。

Looking at the types, and the docs for thaw and freeze :查看类型以及thaw 和 freeze 的文档

thaw :: (Unbox a, PrimMonad m) => Vector a -> m (MVector (PrimState m) a) 

freeze :: (Unbox a, PrimMonad m) => MVector (PrimState m) a -> m (Vector a)

sa mv :: ST s ()

So the do block is inside a monad m in typeclass PrimMonad .所以do块在类型类PrimMonad的单子m内。

My thought was that the ST s would "line up" with that to perform the mutation...我的想法是ST s会与它“排队”以执行突变......

I tried binding that to a hole:我尝试将其绑定到一个洞:

modify sa v = runST $ do
  mv <- V.thaw v
  _ <- sa mv
  V.freeze mv

but that made no difference, which thinking about it, you wouldn't expect it to...但这并没有什么不同,考虑到它,你不会期望它...

I think this is a general question about monad transformers.我认为这是关于 monad 转换器的一般问题。 Is there some lifting I need to do here?我需要在这里做一些提升吗?

What so I need to do to perform the mutation of the mutable vector with my sa ?那么我需要做什么来用我的sa执行可变向量的突变?

Just change the type signature:只需更改类型签名:

modify :: VM.Unbox a => (forall s. VM.MVector s a -> ST s ()) -> V.Vector a -> V.Vector a
--                       ^^^^^^^^^

Your initial implementation was fine.您的初始实施很好。 But, you should use one of the existing modify functions instead of rolling your own.但是,您应该使用现有的modify功能之一,而不是自己滚动。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM