你如何创建一个接收列表的函数" Data.Vector.modify"?

时间:2015-09-05 20:49:31

标签: haskell

Data.Vector具有以下功能:

modify :: (forall s. MVector s a -> ST s ()) -> Vector a -> Vector a

是否可以创建一个函数,例如:

modify :: [(forall s. MVector s a -> ST s ())] -> Vector a -> Vector a

我已经尝试了

{-# LANGUAGE RankNTypes, ImpredicativeTypes #-}

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

unsafeModify :: [(forall s . MV.MVector s Int -> ST s ())] -> V.Vector Int -> V.Vector Int
unsafeModify mods vec = runST $ do
    mvec <- V.unsafeThaw vec
    sequence_ (map ($ mvec) mods)
    V.unsafeFreeze mvec

但是我收到了错误

Muts.hs:11:28:
    Couldn't match type ‘forall s1. V.MVector s1 Int -> ST s1 ()’
                  with ‘V.MVector s Int -> ST s a0’
    Expected type: [V.MVector s Int -> ST s a0]
      Actual type: [forall s. V.MVector s Int -> ST s ()]
    Relevant bindings include
      mvec :: V.MVector s Int (bound at Muts.hs:10:5)
    In the second argument of ‘map’, namely ‘mods’
    In the first argument of ‘sequence’, namely ‘(map ($ mvec) mods)’

4 个答案:

答案 0 :(得分:3)

通常的技巧是收拾你的功能,因此:

data Box a = Box { unBox :: forall s. MVector s a -> ST s () }
modifyAll :: [Box a] -> Vector a -> Vector a
modifyAll fs = modify (\mvector -> mapM_ (\b -> unBox b mvector) fs)

答案 1 :(得分:3)

更改unsafeModify的类型。特别是,将forall s.浮动到列表之外。您希望所有函数共享相同的状态标记(由runST确定),因此您不需要让每个函数都使用另一个 s

{-# LANGUAGE RankNTypes #-}

import qualified Data.Vector.Mutable as MV
import qualified Data.Vector as V
import Control.Monad (mapM_)
import Control.Monad.ST
import Control.Monad.Primitive

unsafeModify :: (forall s . [MV.MVector s Int -> ST s ()]) -> V.Vector Int -> V.Vector Int
unsafeModify mods vec = runST $ do
    mvec <- V.unsafeThaw vec
    mapM_ ($ mvec) mods
    V.unsafeFreeze mvec

答案 2 :(得分:1)

这对我有用:

==>cscript //NOLOGO D:\VB_scripts\SO\32416311.vbs
45       0000000000101101 00000000000000000000000000101101
-45      1111111111010011 11111111111111111111111111010011

==>

答案 3 :(得分:1)

当进行类型检查时,GHC只会实例化具有单形类型的类型变量。自map :: (a -> b) -> [a] -> [b]起,这已经排除了您的预期用法,因为a必须实例化为forall s. MVector s a -> ST s (),而这种情况不可能发生。这是ImpredicativeTypes几乎不可用于GHC的一个原因。

由于我们不能使用通常的高阶流控制函数,我们必须写出一个显式的递归函数:

{-# LANGUAGE ScopedTypeVariables #-}

unsafeModify :: [(forall s . MV.MVector s Int -> ST s ())] -> V.Vector Int -> V.Vector Int
unsafeModify mods vec = runST $ do
  (mvec :: MV.MVector s Int) <- V.unsafeThaw vec

  let go :: [(forall s . MV.MVector s Int -> ST s ())] -> ST s (V.Vector Int)
      go [] = V.unsafeFreeze mvec
      go (mod:mods) = do
        mod mvec
        go mods

  go mods

ScopedTypeVariables也是必要的,因为我们希望s的返回类型中的go与我们绑定s的{​​{1}}相同。