使用GADT进行类型推断 - a0不可触摸 [英] Type inference with GADTs - a0 is untouchable

查看:90
本文介绍了使用GADT进行类型推断 - a0不可触摸的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

可以说我有这个程序

  { - #LANGUAGE GADTs# - } 

data My a where
A :: Int - >我的Int
B :: Char - > My Char


main :: IO()
main = do
let x = undefined :: My a

case x of
A v - >打印v

- 打印x

编译正常。



但是,当我在 print x 中发表评论时,我得到:

 gadt.hs:第13行,第12列:
无法将类型'a0'与'()'相匹配
'a0'不可触及
约束内(a1〜GHC.Types.Int)
由具有构造函数的模式绑定
Main.A :: GHC.Types.Int - > Main.My GHC.Types.Int,
(可选)
at /home/niklas/src/hs/gadt-binary.hs:13:5-7
预期类型:GHC .Types.IO a0
实际类型:GHC.Types.IO()
在表达式中:System.IO.print v
在另一种情况下:Main.A v - > System.IO.print v

为什么我在第13行( A v - >打印v ),而不是仅在打印x 行中?

我认为第一次出现应该确定这种类型。



请赐教:)

解决方法

好吧,首先请注意,这与特定的 print x 没有任何关系:在结束时出现同样的错误。主要与例如 putStrLndone



所以在这种情况下,问题确实存在 do 的最后一条语句需要 c> 块的签名的类型。其他语句只需要在相同的monad中,即 IO a0 而不是 IO()



现在,通常这个 a0 是从语句本身推断出来的,例如,您可以写入

  do getLine 
putStrLn丢弃的输入

尽管 getLine :: IO String 而不是 IO()。但是,在您的示例中,信息 print :: ... - > IO()来自 case 块,来自GADT匹配。而且这样的GADT匹配与其他Haskell语句的行为不同:基本上,它们不会让任何类型信息溢出其范围,因为如果信息来自GADT构造函数,那么在 case



在这个特定的例子中,似乎很明显, a0〜()完全与GADT匹配中的 a1〜Int 有关,但通常情况下,只有GHC追踪所有类型信息的 他们来自哪里。我不知道这是否有可能,它肯定比Haskell的Hindley-Milner系统更复杂,它很大程度上依赖于统一类型信息,它基本上假定信息的位置并不重要



因此,GADT匹配只是作为一个刚性的类型信息二极管:内部的东西永远不能用于确定外部类型,就像 case 块作为一个整体应该是 IO()



然而,你可以手动断言,用相当丑陋的

 (case x of 
A v - > print v
):: IO()

或书写

 ()<  -  case x of 
A v - >打印v


Lets say I have this program

{-# LANGUAGE GADTs #-}

data My a where
  A :: Int  -> My Int
  B :: Char -> My Char


main :: IO ()
main = do
  let x = undefined :: My a

  case x of
    A v -> print v

  -- print x

compiles fine.

But when I comment in the print x, I get:

gadt.hs: line 13, column 12:
  Couldn't match type ‘a0’ with ‘()’
    ‘a0’ is untouchable
      inside the constraints (a1 ~ GHC.Types.Int)
      bound by a pattern with constructor
                 Main.A :: GHC.Types.Int -> Main.My GHC.Types.Int,
               in a case alternative
      at /home/niklas/src/hs/gadt-binary.hs:13:5-7
  Expected type: GHC.Types.IO a0
    Actual type: GHC.Types.IO ()
  In the expression: System.IO.print v
  In a case alternative: Main.A v -> System.IO.print v

Why do I get this error in line 13 (A v -> print v) instead of only in the print x line?

I thought the first occurrence should determine the type.

Please enlighten me :)

解决方案

Well, first note that this has nothing to do with the particular print x: you get the same error when ending main with e.g. putStrLn "done".

So the problem is indeed in the case block, namely in that only the last statement of a do is required to have the type of the do block's signature. The other statements merely have to be in the same monad, i.e. IO a0 rather than IO ().

Now, usually this a0 is inferred from the statement itself, so for instance you can write

do getLine
   putStrLn "discarded input"

though getLine :: IO String rather than IO (). However, in your example the information print :: ... -> IO () comes from inside the case block, from a GADT match. And such GADT matches behave differently from other Haskell statements: basically, they don't let any type information escape its scope, because if the information came from the GADT constructor then it's not correct outside of the case.

In that particular example, it seems obvious enough that a0 ~ () has nothing at all to do with the a1 ~ Int from the GADT match, but in general, such a fact could only be proven if GHC traced for all type information where it came from. I don't know if that's even possible, it would certainly be more complicated than Haskell's Hindley-Milner system, which heavily relies on unifying type information, which essentially assumes that it doesn't matter where the information came from.

Therefore, GADT matches simply act as a rigid “type information diode”: the stuff inside can never be used to determine types on the outside, like that the case block as a whole should be IO ().

However, you can manually assert that, with the rather ugly

  (case x of
     A v -> print v
    ) :: IO ()

or by writing

  () <- case x of
          A v -> print v

这篇关于使用GADT进行类型推断 - a0不可触摸的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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