Существует множество вопросов и ответов о том, что GADTs
лучше, чем DatatypeContexts
, потому что GADT автоматически делают ограничения доступными в нужных местах. Например, здесь, здесь, здесь. Но иногда кажется, что мне все еще нужно явное ограничение. В чем дело? Пример адаптирован из этого ответа:
{-# LANGUAGE GADTs #-}
import Data.Maybe -- fromJust
data GADTBag a where
MkGADTBag :: Eq a => { unGADTBag :: [a] } -> GADTBag a
baz (MkGADTBag x) (Just y) = x == y
baz2 x y = unGADTBag x == fromJust y
-- unGADTBag :: GADTBag a -> [a] -- inferred, no Eq a
-- baz :: GADTBag a -> Maybe [a] -> Bool -- inferred, no Eq a
-- baz2 :: Eq a => GADTBag a -> Maybe [a] -> Bool -- inferred, with Eq a
Почему тип для unGADTBag
не может сообщить нам Eq a
?
baz
и baz2
морально эквивалентны, но имеют разные типы. Предположительно из-за того, что unGADTBag
не имеет Eq a
, ограничение не может распространяться на какой-либо код, использующий unGADTBag
.
Но с baz2
внутри GADTBag a
прячется ограничение Eq a
. Предположительно Eq a
baz2
захочет, чтобы дубликат словаря уже был там (?)
Может быть, у GADT может быть много конструкторов данных, каждый с разными (или без) ограничениями? Это не так здесь или с типичными примерами ограниченных структур данных, таких как сумки, наборы, упорядоченные списки.
Эквивалент для типа данных GADTBag
с использованием DatatypeContexts
подразумевает, что тип baz
совпадает с baz2
.
Бонусный вопрос: почему я не могу получить обычный ... deriving (Eq)
за GADTBag
? Я могу получить один с StandaloneDeriving
, но это совершенно очевидно, почему GHC не может сделать это за меня?
deriving instance (Eq a) => Eq (GADTBag a)
Проблема снова в том, что могут быть другие конструкторы данных?
(Код изучается в GHC 8.6.5, если это актуально.)
Дополнение: в свете ответов @ chi и @ leftroundabout - ни один из них я не считаю убедительным. Все это дает *** Exception: Prelude.undefined
:
*DTContexts> unGADTBag undefined
*DTContexts> unGADTBag $ MkGADTBag undefined
*DTContexts> unGADTBag $ MkGADTBag (undefined :: String)
*DTContexts> unGADTBag $ MkGADTBag (undefined :: [a])
*DTContexts> baz undefined (Just "hello")
*DTContexts> baz (MkGADTBag undefined) (Just "hello")
*DTContexts> baz (MkGADTBag (undefined :: String)) (Just "hello")
*DTContexts> baz2 undefined (Just "hello")
*DTContexts> baz2 (MkGADTBag undefined) (Just "hello")
*DTContexts> baz2 (MkGADTBag (undefined :: String)) (Just "hello")
Принимая во внимание, что эти два выдают ошибку одного и того же типа во время компиляции _27 _ / _ 28_ соответственно [Изменить: мой первоначальный Addit дал неправильное выражение и неправильное сообщение об ошибке]:* Couldn't match expected type ``[Char]'
*DTContexts> baz (MkGADTBag (undefined :: [Int -> Int])) (Just [(+ 1)])
*DTContexts> baz2 (MkGADTBag (undefined :: [Int -> Int])) (Just [(+ 1)])
Итак, baz, baz2
морально эквивалентны не только в том смысле, что они возвращают один и тот же результат для одних и тех же четко определенных аргументов; но также и в том, что они демонстрируют одинаковое поведение для одних и тех же плохо определенных аргументов. Или они отличаются только тем, где сообщается об отсутствии Eq
экземпляра?
@leftroundabout Прежде чем вы фактически деконструируете значение
x
, невозможно узнать, действительно ли применяется конструкторMkGADTBag
.
Да, есть: метка поля unGADTBag
определяется тогда и только тогда, когда есть совпадение с шаблоном на MkGADTBag
. (Возможно, все было бы иначе, если бы для типа существовали другие конструкторы - особенно если бы они также имели метку unGADTBag
.) Опять же, неопределенность / ленивая оценка не откладывают вывод типа.
Чтобы быть ясным, под [не] убедительностью я имею в виду: я могу видеть поведение и предполагаемые типы, которые я получаю. Я не вижу, чтобы лень или потенциальная неопределенность мешали выводу типов. Как я могу выявить разницу между baz, baz2
, которая объяснила бы, почему у них разные типы?
quux x = const x (x == x)
GHC делает выводquux :: Eq a => a -> a
.unGADTBag
требуетMkGADTBag
требуетEq a
так же, какquux
, независимо от того, оценивается ли проверка на равенство или применяетсяEq
словарь. Тогда почемуunGADTBag
теряетEq a
? - person AntC   schedule 05.08.2020