为什么更高级别的类型在Haskell中如此脆弱

分号

我在弄乱runST函数。它具有类型(forall s. ST s a) -> a,并且似乎试图以没有直接使用而没有任何间接方式的任何方式使用它,以非常讨厌的方式破坏它。

runST :: (forall s. ST s a) -> a
const :: a -> b -> a

所以通过替换aconstforall 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

因此auncurry可以肯定地用in替换bin constST,用binuncurry替换(forall s. ST s a)in constST,用ainuncurry替换cin 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 memptyas的类型,Maybe (forall a. Monoid a => a)但是似乎实际使用起来并不容易。我听说强制性类型推断并不是真正可行的方法,但是它将以某种方式将类型推断限制为谓语类型,除非您提供类型签名以其他方式表示。MonoLocalBinds出于类型推断而默认使本地绑定为单态的方式类似

用户名

您已经回答了自己的问题:

...代aconstforall s. ST s a...

这是定义impredictive多态性-实例化一个类型的变量用的能力的多型体,其(松散地)具有一个类型forall在该类型的最左侧量词。

GHC主题页面上:

GHC还不支持强制性多态性

还有

我们已经进行了各种尝试来支持不可思议性,因此有一个标志-XImpredicativeTypes但这是行不通的,并且绝对不受支持。如果您使用它,那您就自己一个人。我不保证会发生什么。

所以不要使用ImpredictiveTypes-它不会有帮助。


现在来看看血腥的细节-为什么所有特定示例都按原样工作?

您已经注意到,在表达式中Just memptyMaybe (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 arunST无法恢复旧类型。


解决此类问题的最简单方法可能是定义一个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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么我的较低级别的日志不写入文件,但错误和更高级别的文件呢?

可以使用更高级别的类型模拟类型级别的类型类吗?

无法实现为字节片绑定的更高级别的生存期类型

属性“调试”已被锁定在更高级别的配置中

如何将多个流合并到更高级别的流中?

在 pandas json 中添加一个更高级别的对象

Lisp中的二进制搜索具有更高级别的功能

返回更高级别的UITableView时的ViewDidLoad

通过更高级别的结构访问子变量

熊猫添加更高级别的列多索引

跨更高级别的容器建立边界

OpenCV SVM总是预测更高级别的标签

如何从更高级别的类别中选择属性

CMake-检查是否存在更高级别的目录

通过更高级别的列合并数据框

Scala - 使用更高级别的方法缩短代码段

将枚举类传播到更高级别的类

为什么类型级别的计算需要Aux技术?

如何在Haskell中获取'[String]的类型级别的值?

如何从批处理脚本的当前路径中获取更高级别的文件夹的名称?

为什么unsigned int在haskell中如此罕见?

为什么使用Google Charts的这段代码如此脆弱?

更高级别聚合的总和

在数据透视后删除更高级别的索引名称

Jackson-将对象内部列表反序列化为更高级别的列表

jQuery addClass仅适用于具有更高级别的div

将参数传递给更高级别的事件处理程序

React-如何在导入的函数中使用更高级别的useState

使用列的唯一值作为更高级别的列熊猫