Алгоритм унификации выводит слишком конкретные типы
-
22-12-2019 - |
Вопрос
Я пытался создать кортежи размера n в Идрисе:
module NTuple
data Tuple : Vect n Type -> Type where
EmptyTuple : Tuple Nil
TupleItem : a -> Tuple types -> Tuple (a :: types)
mapN : {types : Vect n Type} -> (i : Fin (S n)) -> (a -> b) -> Tuple (insertAt i a types) -> Tuple (insertAt i b types)
mapN fZ f (TupleItem x xs) = TupleItem (f x) xs
mapN (fS i) f (TupleItem x xs) = TupleItem x (mapN i f xs)
Но я получаю эту ошибку в последней строке:
When elaborating left hand side of mapN: When elaborating an application of NTuple.mapN: Can't unify Tuple (a :: types) with Tuple (insertAt (fS i) a types) Specifically: Can't unify a :: types with insertAt (fS i) a types
Есть ли способ заставить эту функцию работать?
Решение
Проблема в том, что insertAt (FS i) a types
не может быть уменьшено, ничего не зная о types
.Если бы мы знали types = t :: ts
тогда его можно было бы сократить до t :: insertAt i ts
.
Но во втором случае mapN
, мы делать знай это types
имеет именно такую форму:
- Наш первый аргумент
FS i
- подразумевая
n = S m
для некоторыхm
... - Значение нашего неявного
types
аргумент имеет типVect (S m) Type
- Это означает, что оно имеет вид
t :: ts
!
Как только мы укажем на это Идрису, он будет рад уменьшить insertAt (FS i) a types
и, таким образом, ваш код проверяет тип:
mapN : {types : Vect n Type} -> (i : Fin (S n)) -> (a -> b) -> Tuple (insertAt i a types) -> Tuple (insertAt i b types)
mapN FZ f (TupleItem x xs) = TupleItem (f x) xs
mapN {types = _ :: _} (FS i) f (TupleItem x xs) = TupleItem x (mapN i f xs)
mapN {types = []} (FS i) _ _ = absurd i
Не связан с StackOverflow