可以说我有这个程序
{-# 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
Run Code Online (Sandbox Code Playgroud)
编译好.
但当我评论时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
Run Code Online (Sandbox Code Playgroud)
为什么我在第13行(A v -> print v
)中而不是仅在行中出现此错误print x
?
我认为第一次出现应该确定类型.
请赐教:)
lef*_*out 22
好吧,首先请注意,这与特定内容无关print x
:main
以eg 结尾时会出现相同的错误putStrLn "done"
.
所以这个问题确实是在块的情况下,即在只的最后一条语句do
必须具有类型的的do
块的签名.其他陈述只需要在同一个monad中,IO a0
而不是IO ()
.
现在,通常这a0
是从语句本身推断的,所以例如你可以写
do getLine
putStrLn "discarded input"
Run Code Online (Sandbox Code Playgroud)
虽然getLine :: IO String
而不是IO ()
.但是,在您的示例中,信息print :: ... -> IO ()
来自case
块内部,来自GADT匹配.这样的GADT匹配行为与其他Haskell语句的行为不同:基本上,它们不允许任何类型信息逃避其范围,因为如果信息来自GADT构造函数,那么它不是正确的case
.
在那个特定的例子中,似乎很明显a0 ~ ()
与a1 ~ Int
GADT匹配没有任何关系,但总的来说,这样的事实只有在GHC跟踪它来自的所有类型信息时才能被证明.我不知道这是否可能,它肯定会比Haskell的Hindley-Milner系统更复杂,后者严重依赖于统一类型信息,这基本上假设信息来自何处并不重要.
因此,GADT匹配只是作为一个刚性的"类型信息二极管":内部的东西永远不能用来确定外部的类型,就像case
块整体应该一样IO ()
.
但是,您可以手动断言,相当丑陋
(case x of
A v -> print v
) :: IO ()
Run Code Online (Sandbox Code Playgroud)
或通过写作
() <- case x of
A v -> print v
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
631 次 |
最近记录: |