2014-07-11 61 views
3

我有一个简单的就地函数,我正在使用可变向量来实现。然而,这个函数需要一个最容易使用不变矢量构建的向量。下面是一些玩具代码演示基本结构(但可能不会编译):在可变函数中获取不可变向量的类型

import Data.Vector.Generic as V 
import Data.Vector.Unboxed as U 

myvec :: (Vector v r) => Int -> v r 
myvec i = V.generate i id 

f :: (MVector v r, PrimMonad m) => v (PrimState m) r -> m() 
f y = let v = myvec 10 -- what should the type of `v` be? 
      --the following doesn't work since the Mutable type family is not injective: 
      _ = return v `asTypeOf` unsafeFreeze y 
     in do .... 


main = do 
    -- at the top level, I know the input can be unboxed 
    let v = U.generate 10 (+(1::Int)) 
    v' <- thaw v 
    f v' 
    y <- freeze v' 
    print y 

我没有看到任何方式f确定(有效的)不变载体类型v。我只想让myvec生成一个多态的可变的向量类型,但即使对于上面的简单函数,myvec的代码也更加丑陋。

我正在寻找一个解决方案,让我

  1. 轻松定义myvec(如上定义)(和我没有看到任何方式与可变矢量干净做到这一点)
  2. 用途可能的最具体的矢量类型:例如,一种解决方案是使myvec返回一个盒装矢量,它可以容纳任何r类型。但是,我们担心速度,因此如果f的输入是可变的无框矢量,myvec应该是可变的无框矢量或不可变的无框矢量。
  3. 我也想避免myvec通过从main(其中不变的类型是已知的):我们有足够的信息f生成本地,所以经过矢量从main是没有必要的(除可能用于类型信息)。
+0

你不能传入类型吗? 'f(undefined :: Int)v''?还是有一些GADT可以用来代替Vector类?我不是这方面的专家;只是猜测它。 – dfeuer

+0

我可以将不可变的向量类型从'main'传递给''f'(不确定你在哪里用'undefined :: Int'),但是看起来很疯狂,我应该在完全有效的时候这样做丑陋的)替代方案是把'myvec'写成一个可变的函数。 – crockeea

+0

你想让'myvec'生成的向量被填充到什么地方?如果它将是不可改变的,你需要在创作时知道。目前你已经得到它生成一个'Int'索引的向量。 – rampion

回答

1

经过一番周围挖,我想通了如何编写一个可变generate功能:

import Data.Vector.Generic.Mutable as M 
import Data.Vector.Fusion.Stream as S 
import Control.Monad.Primitive 

mutableGenerate :: (MVector v r, PrimMonad m) => Int -> (Int -> r) -> m (v (PrimState m) r) 
mutableGenerate i f = M.unstream $ S.generate i f 

这让我产生一个多态可变的载体,但有一个不变的向量的简洁符号。在我看来,这应该包含在Data.Vector.Generic.Mutable中。