Как доказать индуктивное равенство типов без классов? - PullRequest
8 голосов
/ 10 апреля 2020

Я пытаюсь доказать ассоциативность списков на уровне типов таким образом, чтобы я мог выполнять преобразование между эквивалентными типами без каких-либо ограничений.

Принимая стандартное определение конкатенации:

type family (++) (xs :: [k]) (ys :: [k]) :: [k] where
  '[] ++ ys = ys
  (x ': xs) ++ ys = x ': (xs ++ ys)

Предположим, у меня есть функция:

given :: forall k (a :: [k]) (b :: [k]) (c :: [k]). Proxy ((a ++ b) ++ c)
given = Proxy  -- Proxy is just an example

, и я хотел бы вызвать эту функцию и затем использовать ассоциативность:

my :: forall k (a :: [k]) (b :: [k]) (c :: [k]). Proxy (a ++ (b ++ c))
my = given @k @a @b @c  -- Couldn't match type ‘(a ++ b) ++ c’ with ‘a ++ (b ++ c)’

Это равенство типов не является тривиальным действительно, поэтому неудивительно, что компилятор этого не понимает, однако я могу это доказать! К сожалению, я не знаю, как убедить компилятор, что я могу.

Моя первая естественная мысль - сделать что-то вроде:

proof :: forall k (a :: [k]) (b :: [k]) (c :: [k]). (a ++ (b ++ c)) :~: ((a ++ b) ++ c)
proof = _

и затем изменить мою функцию на:

my :: forall k (a :: [k]) (b :: [k]) (c :: [k]). Proxy (a ++ (b ++ c))
my = case proof @k @a @b @c of Refl -> given @k @a @b @c

Но я все еще должен определить proof, и для этого мне нужно выполнить индукцию для аргументов его типа. Единственный способ индукции для типов в Haskell, который я знаю, это определить класс типов, но тогда мне придется добавить соответствующее ограничение к типу my, что я не хочу делать - тот факт, что он вызывает given и приводит к результату, является «деталью реализации».

Есть ли способ доказать равенство типов в Haskell без обращения к небезопасным постулатам?

1 Ответ

6 голосов
/ 10 апреля 2020

Нет, вы не можете доказать это без ограничения класса типов, потому что это не так. В частности, вот контрпример:

Any ++ ([] ++ []) -- reduces to Any ++ []
(Any ++ []) ++ [] -- does not reduce

Чтобы исключить (глупое) существование Any, вы должны использовать класс типов, который не имеет экземпляра Any; другого выбора нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...