[英]Haskell type signatures and Monads
我在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
我写的大部分都没有真正试图理解他们做了什么(最后一行),因此,我无法想出合适的类型签名。 但是,编译器介入以保存这一天:
编译器生成的类型签名
vecFromList
:: (PrimMonad (MVector t), PrimState (MVector t) ~ t) =>
[b] -> Int -> MVector t b
我听到有人说Wat吗? 哦,那只是我,无论如何......在我尝试编译它之前,这是我认为应该工作的类型签名:
我认为应该工作的那个
vecFromList :: PrimMonad m => [t] -> Int -> MV.MVector (PrimState m) t
这一点应该是显而易见的,这种看似简单的外观类型签名看起来与我想要的功能完全一样,实际上并不起作用。 为了提出类型签名,我使用了矢量模块中我认为与它类似的一些其他函数的类型签名,例如:
Data.Vector.Mutable.read
:: PrimMonad m => MVector (PrimState m) a -> Int -> m a
现在,我仍然是相对较新的haskell,所以我仍然习惯于习惯语言中使用的符号和符号,特别是接近理解为什么看起来简单的任务必须成为Monands的复杂事物。 例如, MVector
有这种MVector :: * -> * -> *:
的目的是什么MVector :: * -> * -> *:
??
你快到了。 您期望的类型签名是正确的,除了生成的MVector
需要在monad m
:
vecFromList :: PrimMonad m => [t] -> Int -> m (MV.MVector (PrimState m) t)
fillV
函数应该有类型
fillV :: [(Int, t)]
-> MV.MVector (PrimState m) t -> m (MV.MVector (PrimState m) t)
但是你[]
情况给出了向量而没有return
它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
和一个工作的例子:
> V.create $ vecFromList [1,2,3] 3
fromList [1,2,3]
请注意,您不实际修改vec
在fillV
功能,你只引用它,你可以使用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
不幸的是,在Haskell中使用可变向量会变得棘手,需要练习。 使用TypedHoles和PartialTypeSignatures可以提供帮助。
原因MVector
具有PrimState m
,因此它可以与ST
或IO
。 你可以在这里找到它的解释。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.