Haskell 类型签名和 Monad
Haskell type signatures and Monads
我在 haskell 中创建了一个函数,它应该获取一个列表以及列表的大小;并且它应该创建一个具有给定大小的 Data.Vector.Mutable.MVector,用列表的内容填充向量和 return 这个向量。
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
我听到有人说 哇? 哦,那只是我,无论如何......
在我尝试编译它之前,这是我认为应该有效的类型签名:
我觉得应该可以的那个
vecFromList :: PrimMonad m => [t] -> Int -> MV.MVector (PrimState m) t
至此应该很明显,这个看起来有点简单的类型签名看起来与我希望函数执行的操作完全一样,但实际上 没有 工作。为了得出类型签名,我使用了 vector 模块中我认为与之相似的其他一些函数的类型签名,例如:
Data.Vector.Mutable.read
:: PrimMonad m => MVector (PrimState m) a -> Int -> m a
现在,我对 haskell 还是比较陌生,所以我仍在努力适应语言中使用的符号和标志,尤其是接近理解为什么看似简单的任务有由于Monands而变得如此复杂。比如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
将其转换为 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]
请注意,您实际上并没有在 fillV
函数中修改 vec
,您只是引用它,您可以使用 Data.Foldable
中的 for_
函数而不是明确地写一个循环。我通常在 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 and PartialTypeSignatures 会有帮助。
原因 MVector
具有 PrimState m
,因此它可以与 ST
或 IO
一起使用。你可以找到它的解释 here.
我在 haskell 中创建了一个函数,它应该获取一个列表以及列表的大小;并且它应该创建一个具有给定大小的 Data.Vector.Mutable.MVector,用列表的内容填充向量和 return 这个向量。
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
我听到有人说 哇? 哦,那只是我,无论如何...... 在我尝试编译它之前,这是我认为应该有效的类型签名:
我觉得应该可以的那个
vecFromList :: PrimMonad m => [t] -> Int -> MV.MVector (PrimState m) t
至此应该很明显,这个看起来有点简单的类型签名看起来与我希望函数执行的操作完全一样,但实际上 没有 工作。为了得出类型签名,我使用了 vector 模块中我认为与之相似的其他一些函数的类型签名,例如:
Data.Vector.Mutable.read
:: PrimMonad m => MVector (PrimState m) a -> Int -> m a
现在,我对 haskell 还是比较陌生,所以我仍在努力适应语言中使用的符号和标志,尤其是接近理解为什么看似简单的任务有由于Monands而变得如此复杂。比如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
将其转换为 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]
请注意,您实际上并没有在 fillV
函数中修改 vec
,您只是引用它,您可以使用 Data.Foldable
中的 for_
函数而不是明确地写一个循环。我通常在 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 and PartialTypeSignatures 会有帮助。
原因 MVector
具有 PrimState m
,因此它可以与 ST
或 IO
一起使用。你可以找到它的解释 here.