模式中的类型推断

cro*_*eea 6 haskell ghc

我注意到GHC想要一种类型签名,我认为应该推断出来.我把我的例子最小化到了这个,这几乎肯定没有任何意义(我不建议在你最喜欢的类型上运行它):

{-# LANGUAGE GADTs, RankNTypes, ScopedTypeVariables,
             TypeOperators, NoMonomorphismRestriction #-}
module Foo where

import Data.Typeable

data Bar rp rq

data Foo b = Foo (Foo b)


rebar :: forall rp rq rp' rp'' . (Typeable rp', Typeable rp'') 
     => Proxy rp' -> Proxy rp'' -> Foo rp -> Foo (Bar rp rq)
rebar p1 p2 (Foo x) =
  -- The signature for y should be inferred...
  let y = rebar p1 p2 x -- :: Foo (Bar rp rq)
  -- The case statement has nothing to do with the type of y
  in case (eqT :: Maybe (rp' :~: rp'')) of
    Just Refl -> y
Run Code Online (Sandbox Code Playgroud)

如果没有定义的类型签名y,我会得到错误:

Foo.hs:19:20:
    Couldn't match type ‘rq0’ with ‘rq’
      ‘rq0’ is untouchable
        inside the constraints (rp' ~ rp'')
        bound by a pattern with constructor
                   Refl :: forall (k :: BOX) (a1 :: k). a1 :~: a1,
                 in a case alternative
        at testsuite/Foo.hs:19:12-15
      ‘rq’ is a rigid type variable bound by
           the type signature for
             rebar :: (Typeable rp', Typeable rp'') =>
                      Proxy rp' -> Proxy rp'' -> Foo rp -> Foo (Bar rp rq)
           at testsuite/Foo.hs:12:20
    Expected type: Foo (Bar rp rq)
      Actual type: Foo (Bar rp rq0)
    Relevant bindings include
      y :: Foo (Bar rp rq0) (bound at testsuite/Foo.hs:16:7)
      rebar :: Proxy rp' -> Proxy rp'' -> Foo rp -> Foo (Bar rp rq)
        (bound at testsuite/Foo.hs:14:1)
    In the expression: y
    In a case alternative: Just Refl -> y
Failed, modules loaded: none.
Run Code Online (Sandbox Code Playgroud)

我被多个场合的可怕的单态限制所困扰,我开启了NoMonomorphismRestriction,但这并没有改变行为.

为什么y未推断的类型是函数的输出类型?

use*_*038 7

单态限制仅适用于顶级绑定.编译器知道真实的类型y,但没有办法推断它的单形类型; 这是类型错误的原因.如果你真的想关闭单态let绑定,你必须使用正确的扩展:

{-# LANGUAGE NoMonoLocalBinds #-}
Run Code Online (Sandbox Code Playgroud)

有了它,你的代码就可以编译了.

有关单态let绑定的更多详细信息,请参阅ghc wiki.

  • 但是你可能不应该使用`NoMonoLocalBinds`,因为单态本地绑定是由一个(或两个?)所使用的扩展打开的,因为已知这些扩展会因为泛化而表现得不可预测! (2认同)