Haskell类型签名和Monads

sma*_*c89 4 monads haskell vector type-signature

我在haskell中创建了一个函数,它应该列出列表的大小; 并且它应该创建具有给定大小的Data.Vector.Mutable.MVector,用向量的内容填充向量并返回此向量.

TL; DR

  • 我想知道为什么我提供的类型签名不起作用.我错过了什么使它作为类型签名不可接受?
  • 在使用我的类型签名时,是否可以创建一个执行上面指定的功能?
  • 如何根据我编写的代码解释编译器生成的类型签名?

这是功能:

vecFromList lst sz = MV.new sz >>= (\vec -> fillV (zip [0..sz - 1] lst) vec) where
  fillV [] vec = vec 
  fillV ((i, v):xs) vec = MV.write vec i v >> fillV xs vec
Run Code Online (Sandbox Code Playgroud)

我编写的大部分内容并没有真正试图理解他们做了什么(最后一行),因此,我无法想出合适的类型签名.但是,编译器介入以保存这一天:

编译器生成的类型签名

vecFromList
  :: (PrimMonad (MVector t), PrimState (MVector t) ~ t) =>
     [b] -> Int -> MVector t b
Run Code Online (Sandbox Code Playgroud)

我听到有人说Wat吗?哦,那只是我,无论如何......在我尝试编译它之前,这是我认为应该工作的类型签名:

我认为应该工作的那个

vecFromList :: PrimMonad m => [t] -> Int -> MV.MVector (PrimState m) t
Run Code Online (Sandbox Code Playgroud)

这一点应该是显而易见的,这种看似简单的外观类型签名看起来与我想要的功能完全一样,实际上不起作用.为了提出类型签名,我使用了矢量模块中我认为与它类似的一些其他函数的类型签名,例如:

Data.Vector.Mutable.read
  :: PrimMonad m => MVector (PrimState m) a -> Int -> m a
Run Code Online (Sandbox Code Playgroud)

现在,我仍然是相对较新的haskell,所以我仍然习惯于习惯语言中使用的符号和符号,特别是接近理解为什么看似简单的任务必须成为Monands的复杂事物.例如,MVector有这种的目的是什么MVector :: * -> * -> *:

cch*_*ers 5

你快到了.你期望的类型签名是正确的,除非结果MVector需要在monad中m:

vecFromList :: PrimMonad m => [t] -> Int -> m (MV.MVector (PrimState m) t)
Run Code Online (Sandbox Code Playgroud)

fillV函数应该有类型

fillV :: [(Int, t)]
             -> MV.MVector (PrimState m) t -> m (MV.MVector (PrimState m) t)
Run Code Online (Sandbox Code Playgroud)

但你的[]情况是给出了矢量而没有return它的m类型.这是一个工作版本:

vecFromList :: PrimMonad m => [t] -> Int -> m (MV.MVector (PrimState m) t)
vecFromList lst sz = MV.new sz >>= (\vec -> fillV (zip [0..sz - 1] lst) vec) where
  fillV [] vec          = return vec
  fillV ((i, v):xs) vec = MV.write vec i v >> fillV xs vec
Run Code Online (Sandbox Code Playgroud)

和一个工作的例子:

> V.create $ vecFromList [1,2,3] 3
fromList [1,2,3]
Run Code Online (Sandbox Code Playgroud)

请注意,您实际上没有vecfillV函数中修改,只引用它,您可以使用for_函数Data.Foldable而不是显式编写循环.我通常在do块中编写可变向量代码,因为它使我更清楚:

vecFromList2 :: PrimMonad m => [t] -> Int -> m (MV.MVector (PrimState m) t)
vecFromList2 l n = do
  v <- MV.new n
  for_ (zip [0..n - 1] l) $ \(i,a) -> MV.write v i a
  return v
Run Code Online (Sandbox Code Playgroud)

不幸的是,在Haskell中使用可变向量会变得棘手,需要练习.使用TypedHolesPartialTypeSignatures可以提供帮助.

原因MVectorPrimState m它可以使用STIO.你可以在这里找到它的解释.