当我尝试使用proc
语法(使用Netwire和Vinyl)对GADT进行模式匹配时:
sceneRoot = proc inputs -> do
let (Identity camera :& Identity children) = inputs
returnA -< (<*>) (map (rGet draw) children) . pure
我从ghc-7.6.3
得到(相当奇怪的)编译器错误My brain just exploded I can't handle pattern bindings for existential or GADT data constructors. Instead, use a case-expression, or do-notation, to unpack the constructor. In the pattern: Identity cam :& Identity childs
当我将模式放在proc (...)
模式中时,我收到类似的错误。为什么是这样?它不健全,还是只是未实现?
答案 0 :(得分:10)
考虑GADT
data S a where
S :: Show a => S a
并执行代码
foo :: S a -> a -> String
foo s x = case s of
S -> show x
在基于字典的Haskell实现中,可以预期值s
携带类字典,case
从所述字典中提取show
函数,以便{ {1}}可以执行。
如果我们执行
show x
我们得到一个例外。在操作上,这是预期的,因为我们无法访问字典。
更一般地说,foo undefined (\x::Int -> 4::Int)
会产生错误,因为它会强制评估case (undefined :: T) of K -> ...
(假设undefined
不是T
)。
现在考虑代码(让我们假装这个编译)
newtype
并执行
bar :: S a -> a -> String
bar s x = let S = s in show x
这应该怎么办?有人可能认为它应该产生与bar undefined (\x::Int -> 4::Int)
相同的例外。如果是这种情况,参考透明度就意味着
foo
也失败了同样的例外。这意味着let S = undefined :: S (Int->Int) in show (\x::Int -> 4::Int)
正在评估let
表达式,这与例如
undefined
评估为let [] = undefined :: [Int] in 5
。
实际上,5
中的模式是 lazy :与let
不同,它们不会强制对表达式进行求值。这就是为什么,例如。
case
成功评估为let (x,y) = undefined :: (Int,Char) in 5
。
如果5
中需要let S = e in e'
,有人可能希望e
评估show
,但感觉相当奇怪。此外,在评估e'
时,不清楚是评估let S = e1 ; S = e2 in show ...
,e1
还是两者。