Первая попытка
Сложно сделать этот вопрос содержательным, но для минимального примера предположим, что у меня есть такой тип:
{-# LANGUAGE GADTs #-}
data Val where
Val :: Eq a => a -> Val
Этот тип позволяет мне с радостью составить следующий список, выглядящий неоднородно:
l = [Val 5, Val True, Val "Hello!"]
Но, увы, когда я записываю Eq
экземпляр, все идет не так:
instance Eq Val where
(Val x) == (Val y) = x == y -- type error
Ах, значит, мы Could not deduce (a1 ~ a)
. Совершенно верно; в определении ничего не сказано, что x
и y
должны быть одного типа. Фактически, все дело в том, чтобы допустить возможность их различий.
Вторая попытка
Давайте добавим Data.Typeable
в микс и попробуем сравнить их только в том случае, если они одного типа:
data Val2 where
Val2 :: (Eq a, Typeable a) => a -> Val2
instance Eq Val2 where
(Val2 x) == (Val2 y) = fromMaybe False $ (==) x <$> cast y
Это очень мило. Если x
и y
одного типа, используется базовый экземпляр Eq
. Если они отличаются, он просто возвращает False
. Однако эта проверка откладывается до времени выполнения, что позволяет nonsense = Val2 True == Val2 "Hello"
выполнить проверку типов без жалоб.
Вопрос
Я понимаю, что здесь я заигрываю с зависимыми типами, но возможно ли, чтобы система типов Haskell статически отклонила что-то вроде приведенного выше nonsense
, позволяя при этом что-то вроде sensible = Val2 True == Val2 False
возвращать False
во время выполнения?
Чем больше я работаю над этой проблемой, тем больше мне кажется, что мне нужно применять некоторые методы HList для реализации необходимых мне операций как функций уровня типа. Однако я относительно новичок в использовании экзистенциалов и GADT, и мне любопытно узнать, можно ли найти решение именно с ними. Итак, если ответ отрицательный, я был бы очень признателен за обсуждение того, где именно эта проблема достигает предела этих функций, а также за подталкивание к подходящим методам, HList или другим.