Haskell评级为两个多态性编译错误 [英] Haskell rank two polymorphism compile error

查看:89
本文介绍了Haskell评级为两个多态性编译错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定以下定义:

  import Control.Monad.ST 
import Data.STRef

fourty_two = do
x< - newSTRef(42 :: Int)
readSTRef x

以下GHC编译:

  main =(print。runST)fourty_two  - (1)

但这并不是:

  main =(print。runST)$ fourty_two  - (2)

但是,正如 bdonlan 在评论中指出的那样,它会编译:

  main =((print 。runST)$)fourty_two  - (3)

但是,这不会编译

  main =(($)(print。runST))fourty_two  - (4)

这似乎表明(3)只是因特殊处理中缀 $ 而编译,它仍然没有解释为什么(1)会编译。



问题:



1)我已阅读以下两个问题(第一个问题:第一个问题第二个)和我我们相信 $ 只能用单形类型实例化。但我会同样假设只能用单形类型实例化,结果也会失败。
为什么第一个代码成功,但第二个代码不成功? (例如,GHC对第一种情况有特殊规则,它不能在第二种情况下适用)?

2)是否有当前的GHC扩展编译第二个代码? (也许 ImpredicativePolymorphism 在某些时候做了这个,但它似乎不赞成,有什么取代它?)

3)有没有什么办法来定义说 `my_dollar` 使用GHC扩展来完成 $ 的操作,但也可以处理多态类型,所以(print 。runST)`my_dollar` fourty_two 编译?



编辑:建议的答案:

b

另外,以下编译失败:

  main =((。)print runST)fourty_two - (5)

这与(1)相同,除非不使用中缀版本



因此,GHC似乎对 $ ,但只有它们的中缀版本。

解决方案


  1. 我不确定我明白为什么第二个不起作用。我们可以看看 print的类型。 runST 并观察它是足够多态的,所以不应该指责(。)。我怀疑GHC对中缀($)的特殊规则不够充分。 SPJ和朋友可能会开放,重新检查它,如果你提出这个片段作为他们的跟踪器的错误。



    至于第三个例子的工作原理,那就是因为再次,((print。runST)$)的类型足够多态;实际上,它等于 print的类型。 runST


  2. 没有任何内容替代 ImpredicativePolymorphism ,因为GHC人没有看到任何额外的程序员便利超出了编译器错误的额外潜力的用例。 (我不认为他们会将这看作是引人注目的,虽然我当然不是权威。)
  3. 我们可以定义一个稍微少一点的多态<

      { - #LANGUAGE RankNTypes# - } 
    infixl 0 $$
    ($$)::((forall s。fsa) - > b) - > ((forall s。fsa) - > b)
    f $$ x = fx

    然后你的例子使用这个新的操作符进行类型检查:

      * Main> (print。runST)$$ fourty_two 
    42



Given the following definitions:

import Control.Monad.ST
import Data.STRef

fourty_two = do
  x <- newSTRef (42::Int)
  readSTRef x

The following compiles under GHC:

main = (print . runST) fourty_two -- (1)

But this does not:

main = (print . runST) $ fourty_two -- (2)

But then as bdonlan points out in a comment, this does compile:

main = ((print . runST) $) fourty_two -- (3)

But, this does not compile

main = (($) (print . runST)) fourty_two -- (4)

Which seems to indicate that (3) only compiles due to special treatment of infix $, however, it still doesn't explain why (1) does compile.

Questions:

1) I've read the following two questions (first, second), and I've been led to believe $ can only be instantiated with monomorphic types. But I would similarly assume . can only be instantiated with monomorphic types, and as a result would similarly fail. Why does the first code succeed but the second code does not? (e.g. is there a special rule GHC has for the first case that it can't apply in the second?)

2) Is there a current GHC extension that compiles the second code? (perhaps ImpredicativePolymorphism did this at some point, but it seems deprecated, has anything replaced it?)

3) Is there any way to define say `my_dollar` using GHC extensions to do what $ does, but is also able to handle polymorphic types, so (print . runST) `my_dollar` fourty_two compiles?

Edit: Proposed Answer:

Also, the following fails to compile:

main = ((.) print runST) fourty_two -- (5)

This is the same as (1), except not using the infix version of ..

As a result, it seems GHC has special rules for both $ and ., but only their infix versions.

解决方案

  1. I'm not sure I understand why the second doesn't work. We can look at the type of print . runST and observe that it is sufficiently polymorphic, so the blame doesn't lie with (.). I suspect that the special rule that GHC has for infix ($) just isn't quite sufficient. SPJ and friends might be open to re-examining it if you propose this fragment as a bug on their tracker.

    As for why the third example works, well, that's just because again the type of ((print . runST) $) is sufficiently polymorphic; in fact, it's equal to the type of print . runST.

  2. Nothing has replaced ImpredicativePolymorphism, because the GHC folks haven't seen any use cases where the extra programmer convenience outweighed the extra potential for compiler bugs. (I don't think they'd see this as compelling, either, though of course I'm not the authority.)
  3. We can define a slightly less polymorphic ($$):

    {-# LANGUAGE RankNTypes #-}
    infixl 0 $$
    ($$) :: ((forall s. f s a) -> b) -> ((forall s. f s a) -> b)
    f $$ x = f x
    

    Then your example typechecks okay with this new operator:

    *Main> (print . runST) $$ fourty_two
    42
    

这篇关于Haskell评级为两个多态性编译错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆