【发布时间】:2012-05-07 15:37:58
【问题描述】:
给出以下定义:
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) 我已经阅读了以下两个问题(first、second),并且我被引导相信$ 只能用单态类型实例化。但我同样会假设 . 只能用单态类型实例化,因此同样会失败。
为什么第一个代码成功但第二个代码没有? (例如,GHC 是否有针对第一种情况的特殊规则不能在第二种情况下适用?)
2) 当前是否有编译第二个代码的 GHC 扩展? (也许ImpredicativePolymorphism 在某个时候这样做了,但它似乎已被弃用,有什么替代它的吗?)
3) 有没有办法使用 GHC 扩展来定义say `my_dollar` 来做 $ 所做的事情,但也能够处理多态类型,所以 (print . runST) `my_dollar` fourty_two 编译?
编辑:建议的答案:
另外,以下编译失败:
main = ((.) print runST) fourty_two -- (5)
这与(1)相同,只是不使用.的中缀版本。
因此,GHC 似乎对$ 和. 都有特殊规则,但只有它们的中缀版本。
【问题讨论】:
-
为了让它更有趣,
( (print . runST) $ ) fourty_two确实工作 -
这很有趣,而且让事情更加混乱!
-
我相当肯定 GHC 中有一条特殊规则来支持
runST $ do的案例,但我现在找不到引用。 -
@John L:是的,但是带有
$的第二种情况不起作用,但是没有$的第一种情况可以。我想知道为什么第一种情况可以工作,而第二种情况不能工作。 -
要获得真正的答案,您需要找到非常熟悉 GHC 类型检查算法的人。仅供参考,ghc-6.12.3 编译所有表单除了 (3),它抱怨它无法将 forall 类型与
(.)的第二个参数中的单型匹配。因此 ghc-6 和 ghc-7 之间类型检查算法的变化改变了将 forall 类型作为(.)和($)的参数的处理方式。根据我的理解,从他们的类型来看,两者都不应该采用更高级别的类型,但这太不方便了,所以规则变得弯曲了。
标签: haskell polymorphism