我正在弄乱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
,所以每个类型都会感到满意{39} ;看看那是什么无效。
事实证明,使用\_ -> runST
实际上工作正常,并提供正确的类型。
一旦我constST
具有正确的类型,我想看看我是否可以uncurry
,但不出所料,这也会打破。但它似乎真的不应该,但不可否认,这种情况似乎不像前一个那么明显:
constST :: b -> (forall s. ST s a) -> a
uncurry :: (a -> b -> c) -> (a, b) -> c
那么肯定a
中的uncurry
可以替换为b
中的constST
,b
中的uncurry
可以替换使用(forall s. ST s a)
中的constST
和a
中的uncurry
可以替换为c
中的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
正常工作。它正确地将Maybe (forall a. Monoid a => a)
的类型推断为MonoLocalBinds
但似乎实际上使用它并不容易。我听说impredicative类型推断不是真的可行,但它会以某种方式限制对谓词类型的类型推断,除非你提供类型签名来指示其他情况。类似于If you select a single character on the line, tab/shift tab will do the
默认情况下为了类型推断而使局部绑定单态化。
答案 0 :(得分:11)
您已回答了自己的问题:
...将
a
中的const
替换为forall s. ST s a
...
这是 impredictive polymorphism 的定义 - 使用polytype实例化类型变量的能力,它是(松散地)具有forall
量词的类型最左边的那种。
来自主题的GHC trac页:
GHC(尚未)支持不可预测的多态性
此外
我们已经做了各种尝试来支持不信任,因此有一个标志
-XImpredicativeTypes
。但它不起作用,绝对不受支持。如果你使用它,你就是独立的;我对将要发生的事情没有任何承诺。
所以不要使用ImpredictiveTypes
- 它不会帮助。
现在有了血淋淋的细节 - 为什么所有具体的例子都像他们一样工作?
您已注意到在Just mempty
表达式中,不推断出不可预测的类型Maybe (forall a. Monoid a => a)
;相反,forall
已经浮出水面'。您还注意到,对uncurry constST
执行相同的过程会给出一个类型"这是一个更高的等级,但不是不可预测的"。 GHC user guide可以说更高级别的类型:
通常,任意等级类型的类型推断是不可判定的。 ...
对于lambda-bound或case-bound变量x,程序员为x提供显式多态类型,或GHC的类型推断将假设x的类型中没有foralls。
所以你真的必须提供相当多的帮助,这通常会排除使用高阶函数(注意上面说的 nothing 关于任意应用程序,只关于绑定变量 - 和{{1没有绑定变量!)。 uncurry constST
的正确类型是等级1,因此无论是否有其他类型签名,都无法推断它。
例如,您可以编写Just mempty
函数(至少在GHC 8.0.1上):
(forall s. (b, ST s a)) -> a
并且还要注意,您甚至无法对该对进行模式匹配,因为这会立即实例化绑定的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
类型var:
b
使用输入的孔,你得到:
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
,正如GHC trac页面所暗示的那样:
newtype
并存储准备在此容器中运行的newtype RunnableST a = RST (forall s . ST s a)
rrunST :: RunnableST a -> a
rrunST (RST a) = runST a
个操作:
ST
答案 1 :(得分:0)
为了能够编写const runST
,您需要激活Impredicative类型扩展(在GHCi上::set -XImpredicativeTypes
)。