使用 GADT 进行类型推断 - a0 是不可触及的
Type inference with GADTs - a0 is untouchable
假设我有这个程序
{-# 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
编译正常。
但是当我在 print x
中发表评论时,我得到:
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
为什么我在第 13 行 (A v -> print v
) 而不是仅在 print x
行收到此错误?
我认为第一次出现应该确定类型。
请赐教:)
嗯,首先请注意,这与特定的 print x
无关:当 main
以例如结尾时,您会遇到相同的错误。 putStrLn "done"
.
所以问题确实出在 case 块中,即 只有 do
的最后一条语句需要具有 [=16] 的类型 =] 区块的签名。其他语句只需要在同一个 monad 中,即 IO a0
而不是 IO ()
.
现在,通常这个 a0
是从语句本身推断出来的,所以例如你可以写
do getLine
putStrLn "discarded input"
虽然 getLine :: IO String
而不是 IO ()
。但是,在您的示例中,信息 print :: ... -> IO ()
来自 case
块内部, 来自 GADT 匹配 。这种 GADT 匹配的行为与其他 Haskell 语句不同:基本上,它们不会让任何类型信息超出其范围,因为如果信息来自 GADT 构造函数,那么它在 case
之外是不正确的.
在那个特定的例子中,很明显 a0 ~ ()
与 GADT 比赛中的 a1 ~ Int
完全无关,但一般来说,只有在以下情况下才能证明这一事实GHC 追踪了所有类型信息 的来源。我不知道这是否可能,它肯定会比 Haskell 的 Hindley-Milner 系统更复杂,后者严重依赖 unifying 类型信息,这基本上假设信息来自何处并不重要。
因此,GADT 匹配只是作为一个刚性的“类型信息二极管”:里面的东西永远不能用来确定外部的类型,就像 case
块作为一个整体应该是 IO ()
.
但是,您可以手动断言,相当丑陋
(case x of
A v -> print v
) :: IO ()
或写
() <- case x of
A v -> print v
假设我有这个程序
{-# 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
编译正常。
但是当我在 print x
中发表评论时,我得到:
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
为什么我在第 13 行 (A v -> print v
) 而不是仅在 print x
行收到此错误?
我认为第一次出现应该确定类型。
请赐教:)
嗯,首先请注意,这与特定的 print x
无关:当 main
以例如结尾时,您会遇到相同的错误。 putStrLn "done"
.
所以问题确实出在 case 块中,即 只有 do
的最后一条语句需要具有 [=16] 的类型 =] 区块的签名。其他语句只需要在同一个 monad 中,即 IO a0
而不是 IO ()
.
现在,通常这个 a0
是从语句本身推断出来的,所以例如你可以写
do getLine
putStrLn "discarded input"
虽然 getLine :: IO String
而不是 IO ()
。但是,在您的示例中,信息 print :: ... -> IO ()
来自 case
块内部, 来自 GADT 匹配 。这种 GADT 匹配的行为与其他 Haskell 语句不同:基本上,它们不会让任何类型信息超出其范围,因为如果信息来自 GADT 构造函数,那么它在 case
之外是不正确的.
在那个特定的例子中,很明显 a0 ~ ()
与 GADT 比赛中的 a1 ~ Int
完全无关,但一般来说,只有在以下情况下才能证明这一事实GHC 追踪了所有类型信息 的来源。我不知道这是否可能,它肯定会比 Haskell 的 Hindley-Milner 系统更复杂,后者严重依赖 unifying 类型信息,这基本上假设信息来自何处并不重要。
因此,GADT 匹配只是作为一个刚性的“类型信息二极管”:里面的东西永远不能用来确定外部的类型,就像 case
块作为一个整体应该是 IO ()
.
但是,您可以手动断言,相当丑陋
(case x of
A v -> print v
) :: IO ()
或写
() <- case x of
A v -> print v