ST周围的newtype会导致类型错误

时间:2013-09-12 00:25:06

标签: haskell polymorphism higher-rank-types

当我尝试在GHC 7.4.1下加载以下代码时:

{-# LANGUAGE RankNTypes #-}

import Control.Monad.ST

newtype M s a = M { unM :: ST s a }

runM :: (forall s. M s a) -> a
runM (M m) = runST m

它失败并显示以下消息:

test.hs:9:14:
    Couldn't match type `s0' with `s'
      because type variable `s' would escape its scope
    This (rigid, skolem) type variable is bound by
      a type expected by the context: ST s a
    The following variables have types that mention s0
      m :: ST s0 a (bound at test.hs:9:9)
    In the first argument of `runST', namely `m'
    In the expression: runST m
    In an equation for `runM': runM (M m) = runST m

M只是ST的包装时,为什么会失败?

(我的实际程序有一些堆叠在顶部的变压器 - 这只是一个小例子。)


编辑:似乎添加let修复了此问题:

runM m = let M m' = m in runST m

但是,如果启用了TypeFamilies(就像在我的真实代码中那样),它会再次失败。

1 个答案:

答案 0 :(得分:11)

模式匹配+ rankntypes是个问题。

GHC推断m类型为ST ??? a,其中???是一个类型变量,可以与任何东西统一,并且必须与某些东西统一*。然后,我们将其传递给runSTrunST想要ST s am???统一,ss统一。但是等等,现在我们在s范围之外与test (M m) = (m :: forall t . ST t a) `seq` () 进行统一,其中m被定义范围如此灾难。

一个更简单的例子是

t

我们再次收到同样的错误,因为我们尝试使用t test m = runST (unM m) 类型统一,但unM的范围太小。

最简单的解决方案就是不使用

创建此类型变量
ST

此处runST会返回let满意的良好且真实的多态-XTypeFamilies。您可以使用m,因为默认情况下它是多态的,但由于let会让单态变形,它会像您发现的模式匹配一​​样爆炸。


**似乎test :: forall a. (forall t. M t a) -> () test (M m) = (m :: ST Bool a) `seq` (m :: ST Int a) `seq` () 是单态的。 Bool是多态的,没有类型族,所以我怀疑这是正在发生的事情。它表现得像

Int

尝试统一{{1}}和{{1}}的错误正如您对单形类型变量所期望的那样。为什么我发现的每个奇怪的类型错误似乎都隐藏了某种形式的单态变量..