我很担心在Haskell中使用带有多态性的STArray。
假设我有以下设置
data SomeData a = Something a
thawData :: MArray u a m => SomeData a -> m (u Int a)
thawData = {- doesn't matter -}
doSomething :: SomeData a -> ()
doSomething x = runST $ do
xArr <- thawData x
return ()
现在,我相信thawData的类型专门针对这种情况
thawData :: SomeData a -> ST s (STArray Int a)
但是,除非我更改thawData的类型以显式使用STArray,否则这不会编译,即使我尝试在do表达式的主体中显式键入它。
那到底是怎么回事?为什么这种类型不能专门化? 我可以以某种方式改变doSomething的主体而不是thawData的类型吗?
谢谢!
答案 0 :(得分:3)
现在,我相信thawData的类型专门针对这种情况
thawData :: SomeData a -> ST s (STArray Int a)
不完全,STArray
s由状态类型参数化,因此它是ST s (STArray s Int a)
。但无法推断出这一点,因为错误消息告诉您:
Thaw.hs:13:11:
No instance for (MArray u0 a (ST s))
arising from a use of `thawData'
The type variable `u0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance MArray (GHC.Arr.STArray s) e (ST s)
-- Defined in `Data.Array.Base'
instance MArray (Data.Array.Base.STUArray s) Bool (ST s)
-- Defined in `Data.Array.Base'
instance MArray (Data.Array.Base.STUArray s) Char (ST s)
-- Defined in `Data.Array.Base'
...plus 15 others
Possible fix: add an instance declaration for (MArray u0 a (ST s))
In a stmt of a 'do' block: xArr <- thawData x
有MArray
类的几个可能实例ST s
作为monad可供选择(即使只有一个实例在范围内,编译器也会在开放世界假设下运行,其他实例可以在其他地方定义。因此编译器不知道要使用哪个实例,因此它拒绝编译代码。
现在,建议的可能修复程序在这里不正确,您需要的是通过其他方式修复数组类型。一种可能性就是像你一样在顶层专门设置thawData
的类型签名。
另一种方法是将其专门化为doSomething
,而不是
doSomething :: SomeData a -> ()
doSomething x = runST $ do
xArr <- (thawData :: SomeData b -> ST s (STArray s Int b)) x
return ()
告诉编译器在这里使用哪种类型thawData
,第三种是将表达式类型签名移到该行的末尾
{-# LANGUAGE ScopedTypeVariables #-}
-- imports etc.
doSomething :: forall a. SomeData a -> ()
doSomething x = runST $ do
xArr <- thawData x :: ST s (STArray s Int a)
return ()
但是这需要ScopedTypeVariables
扩展名,因为现在您需要从a
的签名中引用实例化类型变量doSomething
的类型。不过,我发现它比行中间的表达式类型签名更具可读性。
答案 1 :(得分:0)
如果您包含错误消息,则会有所帮助。
实际上,我所能做的就是猜测错误是因为你没有提供足够的上下文来确定xArr
的类型。特别是,m
可以与ST s
统一,a
来自参数类型,但没有确定u
的上下文。
我的猜测是编译器告诉你的错误,但由于你没有包含它,这只是猜测。
如果我是对的,你可以通过在thawData
或创建它的表达式上添加类型注释来修改xArr
,从而指定什么类型{{1}应该是。