Деконструкция GADT: где я теряю контекст?
У меня есть этот тип и эти функции:
data Tag a where
Tag :: (Show a, Eq a, Ord a, Storable a, Binary a) => a -> BL.ByteString -> Tag a
getVal :: Tag a -> a
getVal (Tag v _) = v
isBigger :: Tag a -> Tag a -> Bool
a `isBigger` b = (getVal a) > (getVal b)
Код не проверяет тип:
No instance for (Ord a)
arising from a use of `>'
In the expression: (getVal a) > (getVal b)
In an equation for `isBigger':
a isBigger b = (getVal a) > (getVal b)
Но я не могу понять, почему нет. Tag a
имеет контекст (Show a, Eq a, Ord a, Storable a, Binary a)
, а также getVa
Я должен сохранить этот контекст. Я делаю это неправильно или это ограничение расширения GADT?
Это работает:
isBigger :: Tag a -> Tag a -> Bool
(Tag a _) `isBigger` (Tag b _) = a > b
Изменить: я изменил пример на минимальный пример
Редактировать: Хорошо, почему не эта проверка типов?
isBigger :: Tag a -> Tag a -> Bool
isBigger ta tb =
let (Tag a _) = ta
(Tag b _) = tb
in
a > b
1 ответ
Ваш тип подписи для getVal
не правильно, вы хотели бы тип
getVal (Storable a, Ord a, ...) => Tag a -> a
getVal (Tag v _) = v
Причина этого не в том, что вы можете делать такие вещи, как
doh :: Tag a
doh = undefined
Теперь, когда a
не имеет никаких ограничений на это. Мы можем сделать что-то вроде
getVal (doh :: Tag (IO Int)) == getVal (doh :: Tag (IO Int))
если getVal
были те ограничения.
Единственные нижние экземпляры Tag
У вас есть ограничения класса типов, но этого недостаточно для проверки типов с тех пор, как это будет несовместимо с bottom.
Ответить на новый вопрос
Когда вы деконструируете такие типы
foo tag = let (Tag a _) = tag
(Tag b _) = tag
in a > b
GHC не объединяет их должным образом. Я подозреваю, что это потому, что проверщик типов уже определился с типом a
к тому времени, когда будет достигнуто совпадение с образцом, но при сопоставлении с верхним уровнем оно будет правильно объединено.
foo (Tag a _) (Tag b _) = a > b