Haskell 通用量化和统一,一个例子
为运行monadHaskell 通用量化和统一,一个例子,haskell,types,Haskell,Types,为运行monadST runST :: (forall s. ST s a) -> a 以及功能 newVar :: a -> ST s (MutVar s a) readVar :: MutVar s a -> ST s a 然后Haskell编译器将拒绝以下类型错误的表达式 let v = runST (newVar True) in runST (readVar v) 因为为了计算runST,需要 readVar v :: ST s Bool 必须推广到 ∀
ST
runST :: (forall s. ST s a) -> a
以及功能
newVar :: a -> ST s (MutVar s a)
readVar :: MutVar s a -> ST s a
然后Haskell编译器将拒绝以下类型错误的表达式
let v = runST (newVar True)
in runST (readVar v)
因为为了计算runST
,需要
readVar v :: ST s Bool
必须推广到
∀s . ST s Bool
我的问题是,通用量词在这里的唯一工作是确保类型变量
s
在求值上下文中始终是自由的,避免泛化,对吗?或者这里还有关于通用量词的更多信息吗?我想你遗漏了一些东西。GHCi给出的实际信息是:
Prelude> :m +Control.Monad.ST
Prelude Control.Monad.ST> data MutVar s a = MutVar
Prelude Control.Monad.ST> :set -XRankNTypes
Prelude Control.Monad.ST> data MutVar s a = MutVar
Prelude Control.Monad.ST> let readVar = undefined :: MutVar s a -> ST s a
Prelude Control.Monad.ST> let newVar = undefined :: a -> ST s (MutVar s a)
Prelude Control.Monad.ST> runST $ readVar $ runST $ newVar True
<interactive>:14:27:
Couldn't match type ‘s’ with ‘s1’
‘s’ is a rigid type variable bound by
a type expected by the context: ST s Bool at <interactive>:14:1
‘s1’ is a rigid type variable bound by
a type expected by the context: ST s1 (MutVar s Bool)
at <interactive>:14:19
Expected type: ST s1 (MutVar s Bool)
Actual type: ST s1 (MutVar s1 Bool)
In the second argument of ‘($)’, namely ‘newVar True’
In the second argument of ‘($)’, namely ‘runST $ newVar True’
前奏曲>:m+Control.Monad.ST
前奏曲控件.Monad.ST>数据MutVar s a=MutVar
前奏曲控制.Monad.ST>:set-XRankNTypes
前奏曲控件.Monad.ST>数据MutVar s a=MutVar
Prelude Control.Monad.ST>let readVar=undefined::MutVar s a->ST s a
Prelude Control.Monad.ST>let newVar=undefined::a->ST s(MutVar s a)
Prelude Control.Monad.ST>runST$readVar$runST$newVar True
:14:27:
无法将类型“s”与“s1”匹配
“s”是一个刚性类型变量,由
上下文所需的类型:ST s Bool at:14:1
“s1”是一个刚性类型变量,由
上下文所需的类型:ST s1(MutVar s Bool)
时间:14:19
预期类型:ST s1(多变量s布尔)
实际类型:ST s1(多变量s1布尔)
在“($)”的第二个参数中,即“newVar True”
在“($)”的第二个参数中,即“runST$newVar True”
Haskell编译器拒绝它不是因为与
readVar
有任何关系,而是因为newVar
有一个问题,即sts(MutVar sa)
允许s
通过跳入MutVar
表达式来“逃逸”其上下文。让我们看看runST
的类型。我还为a
添加了一个显式的四元组
runST :: forall a . (forall s. ST s a) -> a
合同内容如下:
a
x
s
的任何选择,参数x
必须是ST s a
类型。换句话说,s
将由runST
选择,而不是由调用者选择runFoo :: forall a . (forall s. s -> [(s,a)]) -> [a]
runFoo x =
let part1 = x "hello!" -- here s is String
-- part1 has type [(String, a)]
part2 = x 'a' -- here s is Char
-- part2 has type [(Char, a)]
part3 = x (map snd part2) -- here s is [a] (!!!)
-- part3 has type [([a],a)]
in map snd part1 ++ map snd part2 ++ map snd part3
test1 :: [Int]
test1 = runFoo (\y -> [(y,2),(y,5)]) -- here a is Int
test2 :: [Int]
test2 = runFoo (\y -> [("abc" ++ y,2)]) -- ** error
-- I can't choose y :: String, runFoo will choose that type!
请注意,a
是固定的(到Int
),并且我不能对y
的类型设置任何限制。此外:
test3 = runFoo (\y -> [(y,y)]) -- ** error
在这里,我不是预先修复a
,而是尝试选择a=s
。我不允许这样做:runFoo
可以根据a
选择s
(请参见上文part3
),因此a
必须提前修复
现在,以你为例。问题在于
runST (newSTRef ...)
在这里,newSTRef
返回一个ST s(STRef s Int)
,因此它试图选择a=STRef s Int
。由于a
依赖于s
,因此此选项无效
ST
monad使用此“技巧”来防止引用monad中的“转义”。也就是说,可以保证在runST
返回后,所有引用现在都不再可访问(并且可能会被垃圾收集)。因此,ST
计算过程中使用的可变状态被丢弃,而runST
的结果实际上是一个纯值。毕竟,这是ST
monad的主要目的:它意味着允许在纯计算中使用(临时)可变状态。您所说的“在评估上下文中始终自由,避免泛化”是什么意思?我想你可能对此有正确的想法,但我无法解析这个句子。如果我错了,请更正。在上下文Γ中推广t型,需要量化t的自由变量,这些变量不是在Γ上自由出现的。我的意思是,因为s在t和Γ中都是自由的,所以这个类型不能被推广,然后被拒绝。