我在弄乱runST
函数。它具有类型(forall s. ST s a) -> a
,并且似乎试图以没有直接使用而没有任何间接方式的任何方式使用它,以非常讨厌的方式破坏它。
runST :: (forall s. ST s a) -> a
const :: a -> b -> a
所以通过替换a
在const
为forall s. ST s a
你应该得到的类型const runST
const runST :: b -> (forall s. ST s a) -> a
但是相反,GHC表示它不能a
与之匹配,(forall s. ST s a) -> a
但是因为a
从字面上意味着forall a. a
每种类型都可以满足,所以我看不出有什么无效的地方。
事实证明,使用\_ -> runST
代替实际上可以正常工作并提供正确的类型。
一旦有了constST
正确的类型,我就想看看是否可以uncurry
,但这不足为奇。但似乎确实不应该这样做,尽管可以肯定的是,这种情况似乎不如前一种情况明显:
constST :: b -> (forall s. ST s a) -> a
uncurry :: (a -> b -> c) -> (a, b) -> c
因此a
,uncurry
可以肯定地用in替换b
in constST
,用b
inuncurry
替换(forall s. ST s a)
in constST
,用a
inuncurry
替换c
in constST
。这给我们:
uncurry constST :: (b, forall s. ST s a) -> a
现在承认这种类型是强制性的,我知道这是有问题的。但是Just mempty
在直接替换而不移动隐式forall
量化时,从技术上讲也是必不可少的。
Just :: a -> Maybe a
mempty :: forall a. Monoid a => a
Just mempty :: Maybe (forall a. Monoid a => a)
但是forall
会自动浮动,为您提供:
Just mempty :: forall a. Monoid a => Maybe a
现在,如果我们做相同的事情,uncurry constST
我们应该明智并据我所知正确的类型:
uncurry constST :: (forall s. (b, ST s a)) -> a
排名较高,但不是强制性的。
有人可以向我解释为什么以上这些基本上基本上都不与GHC 8一起使用吗,在一般情况下是否有更根本的因素使上述内容非常复杂?因为如果没有它看起来像这将是非常不错的,上面的工作,如果仅仅是为了摆脱恼人的特殊外壳$
为求纯粹runST
。
顺便说一句,有可能代替所有forall
浮动,我们可以ImpredicativeTypes
正常工作了。它可以正确地推断Just mempty
as的类型,Maybe (forall a. Monoid a => a)
但是似乎实际使用起来并不容易。我听说强制性类型推断并不是真正可行的方法,但是它将以某种方式将类型推断限制为谓语类型,除非您提供类型签名以其他方式表示。与MonoLocalBinds
出于类型推断而默认使本地绑定为单态的方式类似。
您已经回答了自己的问题:
...代
a
中const
的forall s. ST s a
...
这是定义impredictive多态性-实例化一个类型的变量用的能力的多型体,其(松散地)具有一个类型forall
在该类型的最左侧量词。
在GHC主题页面上:
GHC还不支持强制性多态性
还有
我们已经进行了各种尝试来支持不可思议性,因此有一个标志
-XImpredicativeTypes
。但这是行不通的,并且绝对不受支持。如果您使用它,那您就自己一个人。我不保证会发生什么。
所以不要使用ImpredictiveTypes
-它不会有帮助。
现在来看看血腥的细节-为什么所有特定示例都按原样工作?
您已经注意到,在表达式中Just mempty
,Maybe (forall a. Monoid a => a)
不推断类型是不可推断的。而是forall
“浮动”。您还注意到,对执行相同的过程将uncurry constST
给出类型“等级较高但不是强制性的”。该GHC用户指南有这样说的更高级别的类型:
通常,对于任意秩类型的类型推断是不确定的。...
对于x的lambda绑定变量或大小写绑定变量,程序员可以为x提供一个显式的多态类型,否则GHC的类型推断将假定x的类型中没有forall。
因此,您确实必须提供很多帮助,并且通常不能一起使用高阶函数(请注意,以上内容对任意应用程序一无所知,仅涉及绑定变量,而uncurry constST
没有绑定变量!)。正确的类型Just mempty
是等级1,因此在有或没有其他类型签名的情况下,推断它的问题都没有。
例如,您可以这样编写(forall s. (b, ST s a)) -> a
函数(至少在GHC 8.0.1上):
constST' :: forall a b . (forall s . (b, ST s a)) -> a
constST' z = runST z'
where z' :: forall s . ST s a
z' = snd z
还要注意,您甚至无法在该对上进行模式匹配,因为这会立即实例化绑定b
类型var:
constST' :: forall a b . (forall s . (b, ST s a)) -> a
constST' (a,b) = _res
使用打孔,您将得到:
* Found hole: _res :: a
Where: `a' is a rigid type variable bound by
the type signature for:
constST' :: forall a b. (forall s. (b, ST s a)) -> a
* In the expression: _res
In an equation for constST': constST' (a, b) = _res
* Relevant bindings include
b :: ST s0 a
a :: b
需要注意的类型b
就是ST s0 a
一些清爽型的变量 s0
,而不是必需forall s . ST s a
的runST
。无法恢复旧类型。
解决此类问题的最简单方法可能是定义一个newtype
,如GHC追踪页面所建议的:
newtype RunnableST a = RST (forall s . ST s a)
rrunST :: RunnableST a -> a
rrunST (RST a) = runST a
并ST
在此容器中存储可以运行的操作:
doSomething :: RunnableST X
doSomething = RST $ do ...
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句