Я изучаю idris и очень заинтересован в доказательстве свойств списков.
Если вы посмотрите на стандартная библиотека, есть доказательство того, что "Два списка равны, если их головы и хвосты равны".
consCong2 : {x : a} -> {xs : List a} -> {y : b} -> {ys : List b} ->
x = y -> xs = ys -> x :: xs = y :: ys
consCong2 Refl Refl = Refl
Мы также можем доказать другое направление
consCong2' : {x : a} -> {xs : List a} -> {y : b} -> {ys : List b} ->
x::xs = y::ys -> x = y -> xs = ys
consCong2' Refl Refl = Refl
Или, что еще более явно, мы можем отбросить головы с обеих сторон уравнений, чтобы перейти к доказательству.
consCong2' : {x : a} -> {xs : List a} -> {y : b} -> {ys : List b} ->
x::xs = y::ys -> x = y -> xs = ys
consCong2' prf_cons Refl = (cong {f = drop 1} prf_cons)
Было бы интересно посмотреть, можно ли доказать эти свойства также для последнего элемента в остальных и всего, что было до него. Доказать «Два списка равны, если равны первая часть и самый последний элемент» оказалось очень просто
consCong2' : {x : a} -> {xs : List a} -> {y : b} -> {ys : List b} ->
x = y -> xs = ys -> xs ++ [x] = ys ++ [y]
consCong2' Refl Refl = Refl
Но в другом направлении проверка типа не проходит:
consCong2' : {x : a} -> {xs : List a} -> {y : b} -> {ys : List b} ->
xs ++ [x] = ys ++ [y] -> x = y -> xs = ys
consCong2' Refl Refl = Refl
Так как
Type mismatch between
ys ++ [x]
and
xs ++ [x]
Очевидно, потому что если xs ++ [x] = ys ++ [y]
будет первым в выводе, Идрис не сможет объединить обе стороны.
Так что все, что нам нужно сделать, это сказать idris применить init
к обеим частям уравнения, как мы сделали раньше с drop 1
. Это не удается, потому что init требует доказательства того, что список не пуст, что каким-то образом не может быть здесь неявно выведено. Поэтому для этого я написал вспомогательную функцию, которая явно определяет (a ++ [x]) = a
.
dropOneRight : (xs : List a) -> List a
dropOneRight xs with (snocList xs)
dropOneRight [] | Empty = []
dropOneRight (a ++ [x]) | Snoc rec = a
consCong2' : {x : a} -> {xs : List a} -> {y : b} -> {ys : List b} ->
xs ++ [x] = ys ++ [y] -> x = y -> xs = ys
consCong2' prf_cons Refl = cong {f = dropOneRight} prf_cons
Но это дает
Type mismatch between
dropOneRight (ys ++ [x])
and
ys
Я трачу некоторое время на другие подходы, разделяя регистр с помощью snocList
, но не могу добиться заметного прогресса. Я не понимаю, как я могу показать Идрису, что dropOneRight (ys ++ [x]) = ys
. Как я могу доказать xs ++ [x] = ys ++ [y] -> x = y -> xs = ys
?
x = y
иxs = ys
. - person gallais   schedule 12.09.2019