Я пытаюсь понять, как перейти к «безопасно набранному» коду. Например, ниже предполагается вызывать tail
только на безопасном пути, т.е. если список на входе непуст. Конечно, был бы простой способ просто сопоставить список с образцом, но идея состоит в том, чтобы согласовать результат функции (null
) и ее использование в правой части:
data Void : Set where
data _==_ {A : Set} (x : A) : A -> Set where
refl : x == x
data Bool : Set where
True : Bool
False : Bool
data List (A : Set) : Set where
nil : List A
_::_ : A -> List A -> List A
null : forall {A} -> List A -> Bool
null nil = True
null (x :: xs) = False
non-null : forall {A} -> List A -> Set
non-null nil = Void
non-null (x :: xs) = (x :: xs) == (x :: xs)
tail : forall {A} -> (xs : List A) -> {p : non-null xs} -> List A
tail (_ :: xs) = xs
tail nil {p = ()}
prove-non-null : forall {A} -> (xs : List A) -> (null xs == False) -> non-null xs
prove-non-null nil ()
prove-non-null (x :: xs) refl = refl
compileme : forall {A} -> List A -> List A
compileme xs with null xs
... | True = xs
... | False = tail xs {prove-non-null xs refl}
В последней строке agda жалуется, что нельзя доказать, что refl
относится к типу null xs == False
. Почему он не видит, что предложение with только что стало свидетелем того, что null xs
является False
?
Как правильно это сделать? Как "извлечь" зависимость из вроде бы независимых результатов, типа Bool
тип не зависит от списка xs
, но в контексте он есть?