[英]Haskell mutable vector in record
I'm trying to create a record that contains a mutable vector and then print the record.我正在尝试创建一个包含可变向量的记录,然后打印该记录。
import qualified Data.Vector.Mutable as VM
data Foo s = Foo {bar :: VM.STVector s Int}
I have a function that creates an instance ok,我有一个创建实例的 function ok,
mkFoo :: PrimMonad m => m (Foo (PrimState m))
mkFoo = do
b <- VM.generate 5 (const 3)
return Foo {bar = b}
When I try to create a function that prints the record, though, it's giving errors.但是,当我尝试创建打印记录的 function 时,它会出错。
printFoo :: PrimMonad m => m (Foo (PrimState m)) -> IO ()
printFoo f = do
let b = bar f
printf "%d\n" (VM.read b 0)
It's giving the error,它给出了错误,
* Couldn't match type `m' with `Foo'
`m' is a rigid type variable bound by
the type signature for:
printFoo :: forall (m :: * -> *).
PrimMonad m =>
m (Foo (PrimState m)) -> IO ()
What's the trick to being able to get at the mutable data?获取可变数据的诀窍是什么?
First of all, I would recommend sticking to IO
at this point and look at ST
and PrimMonad
later as they are more complicated.首先,我建议此时坚持使用IO
,稍后再看ST
和PrimMonad
,因为它们更复杂。 For your program that would look like this:对于您的程序,看起来像这样:
import qualified Data.Vector.Mutable as VM
import Text.Printf
data Foo = Foo { bar :: VM.IOVector Int }
mkFoo :: IO Foo
mkFoo = do
b <- VM.generate 5 (const 3)
return Foo {bar = b}
printFoo :: IO Foo -> IO ()
printFoo f = do
let b = bar f
printf "%d\n" (VM.read b 0)
Now the first error you get is:现在你得到的第一个错误是:
M.hs:13:15: error:
• Couldn't match expected type ‘Foo’ with actual type ‘IO Foo’
• In the first argument of ‘bar’, namely ‘f’
In the expression: bar f
In an equation for ‘b’: b = bar f
|
13 | let b = bar f
| ^
This message tells you that the function bar
expects a value of type Foo
as input, but you give it a value of type IO Foo
.此消息告诉您 function bar
需要一个Foo
类型的值作为输入,但您给它一个IO Foo
类型的值。 There are multiple ways to fix this.有多种方法可以解决此问题。 Since this function runs in IO
we can first unwrap the argument like this:由于这个 function 在IO
中运行,我们可以首先像这样解开参数:
printFoo :: IO Foo -> IO ()
printFoo f = do
f' <- f
let b = bar f'
printf "%d\n" (VM.read b 0)
However, I would say this is not very idiomatic.但是,我会说这不是很地道。 Instead it is more useful to require that the input to your function is already unwrapped, like this:相反,要求 function 的输入已经解包会更有用,如下所示:
printFoo :: Foo -> IO ()
printFoo f = do
let b = bar f
printf "%d\n" (VM.read b 0)
Now you will still get another error message (GHC versions before 9.0.1 will show a less readable error):现在您仍然会收到另一条错误消息(9.0.1 之前的 GHC 版本将显示可读性较差的错误):
/tmp/M.hs:9:26: error:
• Couldn't match type ‘Control.Monad.Primitive.PrimState m0’
with ‘GHC.Prim.RealWorld’
Expected: VM.MVector (Control.Monad.Primitive.PrimState m0) Int
Actual: VM.IOVector Int
The type variable ‘m0’ is ambiguous
• In the first argument of ‘VM.read’, namely ‘b’
In the second argument of ‘printf’, namely ‘(VM.read b 0)’
In a stmt of a 'do' block: printf "%d\n" (VM.read b 0)
|
9 | printf "%d\n" (VM.read b 0)
| ^
This error is vague, because the VM.read
function can be used in many different ways and it is not clear which way you intend.这个错误是模糊的,因为VM.read
function 可以以多种不同的方式使用,并且不清楚您想要哪种方式。 If you write the explicit type signature VM.read:: VM.IOVector a -> Int -> IO a
,like this:如果你写显式类型签名VM.read:: VM.IOVector a -> Int -> IO a
,像这样:
printFoo :: Foo -> IO ()
printFoo f = do
let b = bar f
printf "%d\n" ((VM.read :: VM.IOVector a -> Int -> IO a) b 0)
(You could also use the TypeApplications
extension and write VM.read @IO b 0
) (您也可以使用TypeApplications
扩展并编写VM.read @IO b 0
)
Then the error message becomes clearer:然后错误消息变得更加清晰:
M.hs:14:3: error:
• No instance for (PrintfArg (IO Int))
arising from a use of ‘printf’
• In a stmt of a 'do' block:
printf "%d\n" ((VM.read :: VM.IOVector a -> Int -> IO a) b 0)
In the expression:
do let b = bar f
printf "%d\n" ((VM.read :: VM.IOVector a -> Int -> IO a) b 0)
In an equation for ‘printFoo’:
printFoo f
= do let b = ...
printf "%d\n" ((VM.read :: VM.IOVector a -> Int -> IO a) b 0)
|
14 | printf "%d\n" ((VM.read :: VM.IOVector a -> Int -> IO a) b 0)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This tells you that you cannot use a value of type IO Int
as an argument to the printf
function.这告诉您不能使用IO Int
类型的值作为printf
function 的参数。 In this case the fix is simply to unwrap the value before printing it:在这种情况下,修复只是在打印之前解开该值:
printFoo :: Foo -> IO ()
printFoo f = do
let b = bar f
x <- VM.read b 0
printf "%d\n" x
Now the file compiles without errors, but how do you actually use these functions?现在文件编译没有错误,但你如何实际使用这些函数? If you naively try to call printFoo mkFoo
then you will again get an error about not being able to match the expected type Foo
with the actual type IO Foo
.如果您天真地尝试调用printFoo mkFoo
,那么您将再次收到一个错误,即无法将预期类型Foo
与实际类型IO Foo
匹配。 Again the solution is to unwrap, in GHCi you can do that like this:同样,解决方案是展开,在 GHCi 中,您可以这样做:
ghci> f <- mkFoo
ghci> printFoo f
3
If you want to use this in another function then you can do that similarly, for example in the main function:如果您想在另一个 function 中使用它,那么您可以类似地执行此操作,例如在主 function 中:
main :: IO ()
main = do
f <- mkFoo
printFoo f
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.