给出以下签名来运行monad 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
在评估环境中始终是免费的,避免泛化,我是对的吗?或者这里有更多关于通用量词的内容吗?
答案 0 :(得分:6)
让我们读一下runST
的类型。我也为a
添加了明确的quatifier。
runST :: forall a . (forall s. ST s a) -> a
它读作以下合同:
a
x
x
的任何选择,参数ST s a
必须为s
类型。换句话说,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
被允许根据s
选择a
(请参阅上面的part3
),因此必须修复a
提前。
现在,举个例子。问题在于
runST (newSTRef ...)
此处,newSTRef
会返回ST s (STRef s Int)
,因此它会尝试选择a = STRef s Int
。由于a
取决于s
,因此该选项无效。
这个"技巧"由ST
monad用于防止引用" escape"来自monad。也就是说,保证在runST
返回之后,现在不再可以访问所有引用(并且可能它们可以被垃圾收集)。因此,ST
计算期间使用的可变状态已被丢弃,runST
的结果确实是纯值。毕竟,这是ST
monad的主要目的:它意味着允许(临时)可变状态用于纯计算。
答案 1 :(得分:1)
我认为你错过了什么。 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’
Haskell编译器拒绝它,不是因为任何与readVar
有关,而是因为newVar
存在问题,ST s (MutVar s a)
允许s
到&#34;逃避&#34;跳转到MutVar
表达式的上下文。