Странное сообщение об ошибке GHC, "Мой мозг только что взорвался"?
Когда я пытаюсь сопоставить шаблон GADT в proc
синтаксис (с Netwire и Vinyl):
sceneRoot = proc inputs -> do
let (Identity camera :& Identity children) = inputs
returnA -< (<*>) (map (rGet draw) children) . pure
Я получаю (довольно странную) ошибку компилятора из ghc-7.6.3
Мой мозг только что взорвался Я не могу обработать привязки к шаблону для конструкторов GADT или экзистенциальных данных. Вместо этого используйте case-выражение или do-notation, чтобы распаковать конструктор. В шаблоне: Идентификационная камера:& Идентификационные данные ребенка
Я получаю похожую ошибку, когда я помещаю шаблон в proc (...)
шаблон. Почему это? Это несостоятельно или просто не реализовано?
1 ответ
Рассмотрим ГАДТ
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
функция из указанного словаря, так что 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
,
Действительно, шаблоны в 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
, e2
, или оба.
GHC на данный момент решает запретить все эти случаи с помощью простого правила: никаких ленивых шаблонов при устранении GADT.