Запомните следующий тип данных:
data AB : Set where
A : AB -> AB
B : AB -> AB
C : AB
rwt : AB -> AB
rwt (B (A ab)) = rwt ab
rwt (A ab) = A (rwt ab)
rwt (B ab) = B (rwt ab)
rwt C = C
ab : AB
ab = rwt (rwt (B (B (A (A (A (A (B (B (A (B C)))))))))))
Здесь rwt
предназначен для замены всех вхождений B (A x)
на x
. Однако то, как оно написано, не гарантирует, что результат будет в нормальной форме, что видно по тому факту, что нам потребовалось два приложения rwt
, чтобы добраться до A (A (B (B x)))
, которые нельзя переписать дальше.
Есть ли способ написать reduce : AB -> AB
в Agda, который будет возвращать тот же результат, как если бы мы неоднократно вызывали rewrite
до тех пор, пока не останется B (A x)
? И мы можем также получить доказательство этого (возможно reduce : (input : AB) -> Σ AB (λ output . is-reduction-of input && is-in-nf output
)?
Попытка:
Приведенная ниже программа всегда возвращает нормальную форму ab
:
reduce : AB -> ℕ -> AB
reduce (A ab) (suc n) = reduce ab n
reduce (A ab) zero = A (reduce ab zero)
reduce (B ab) n = reduce ab (suc n)
reduce C (suc n) = B (reduce C n)
reduce C zero = C
Но как мы можем доказать, что он на самом деле возвращает термин без "redexes" и что он эквивалентен rwt (rwt (rwt ... ab))
? Я спрашиваю, потому что я ожидаю, что найдутся популярные методы для решения этой ситуации.