У меня возникла проблема с проверкой завершения, очень похожей на ту, что описана в this question, а также на этот Agda bug report/feature request.Проверка окончания соединения с
Проблема заключается в том, чтобы убедить компилятор, что следующие unionWith
завершается. Используя функцию объединения для дубликатов ключей, unionWith
объединяет две карты, представленные в виде списков пар (ключ, значение), отсортированных по ключу. Параметр Key конечного отображения является (негибкой) нижней границей ключей, содержащихся на карте. (Одна из причин для определения этого типа данных является предоставление семантическую область, в которую я могу интерпретировать AVL деревья, чтобы доказать различные свойства о них.)
open import Function
open import Relation.Binary renaming (IsEquivalence to IsEq)
open import Relation.Binary.PropositionalEquality as P using (_≡_)
module FiniteMap
{k v ℓ ℓ′}
{Key : Set k}
(Value : Set v)
{_<_ : Rel Key ℓ}
(isStrictTotalOrder : IsStrictTotalOrder _≡_ _<_)
{_≈_ : Rel Value ℓ′}
(isEquivalence : IsEq _≈_)
where
open import Algebra.FunctionProperties
open import Data.Product
open IsStrictTotalOrder isStrictTotalOrder
open import Level
KV : Set (k ⊔ v)
KV = Key × Value
data FiniteMap (l : Key) : Set (k ⊔ v ⊔ ℓ) where
[] : FiniteMap l
_∷_ : (kv : KV) → let k = proj₁ kv in l < k → (m : FiniteMap k) → FiniteMap l
unionWith : ∀ {l} → Op₂ Value → Op₂ (FiniteMap l)
unionWith _ [] [] = []
unionWith _ [] m = m
unionWith _ m [] = m
unionWith _⊕_ (_∷_ (k , v) k<l m) (_∷_ (k′ , v′) k′<l m′) with compare k k′
... | tri< k<k′ _ _ = _∷_ (k , v) k<l (unionWith _⊕_ m (_∷_ (k′ , v′) k<k′ m′))
... | tri≈ _ k≡k′ _ rewrite P.sym k≡k′ = {!!} --_∷_ (k , v ⊕ v′) k<l (unionWith _⊕_ m m′)
... | tri> _ _ k′<k = _∷_ (k′ , v′) k′<l (unionWith _⊕_ (_∷_ (k , v) k′<k m) m′)
я не смог обобщить решения, описанные в referenced question в мою настройку. Например, если я ввести вспомогательную функцию unionWith'
, определенное взаимно рекурсивно с unionWith
, который вызывается из последних в k' < k
случае:
unionWith : ∀ {l} → Op₂ Value → Op₂ (FiniteMap l)
unionWith′ : ∀ {l} → Op₂ Value → (kv : KV) → let k = proj₁ kv in l < k → FiniteMap k → Op₁ (FiniteMap l)
unionWith _ [] [] = []
unionWith _ [] m = m
unionWith _ m [] = m
unionWith _⊕_ (_∷_ (k , v) k<l m) (_∷_ (k′ , v′) k′<l m′) with compare k k′
... | tri< k<k′ _ _ = _∷_ (k , v) k<l (unionWith _⊕_ m (_∷_ (k′ , v′) k<k′ m′))
... | tri≈ _ k≡k′ _ rewrite P.sym k≡k′ = {!!} --_∷_ (k , v ⊕ v′) k<l (unionWith _⊕_ m m′)
... | tri> _ _ k′<k = _∷_ (k′ , v′) k′<l (unionWith′ _⊕_ (k , v) k′<k m m′)
unionWith′ _ (k , v) l<k m [] = _∷_ (k , v) l<k m
unionWith′ _⊕_ (k , v) l<k m (_∷_ (k′ , v′) k′<l m′) with compare k k′
... | tri< k<k′ _ _ = {!!}
... | tri≈ _ k≡k′ _ = {!!}
... | tri> _ _ k′<k = _∷_ (k′ , v′) k′<l (unionWith′ _⊕_ (k , v) k′<k m m′)
тогда как только я связать рекурсивный узел, заменив первый недостающий случай unionWith'
с требуемым вызовом unionWith
, он не может завершить проверку.
Я также попытался представить дополнительные шаблоны with
, но это сложно из-за необходимости использовать результат compare
в рекурсивных вызовах. (Если я использую вложенные with
статьи, которые, похоже, не помогают методу завершения проверки.)
Есть ли способ использовать with
шаблоны или вспомогательные функции для компиляции? Похоже, ситуация достаточно проста, поэтому я надеюсь, что это всего лишь случай, когда вы поймете, какой трюк.
(Может быть, новое прекращение проверки в отрасли разработки Агда может справиться с этим, но я хотел бы избежать установки разрабатываемой версии, если я не должен.)
Вы можете проверить вторую версию ('unionWith'') с' {- # OPTIONS -termination-depth = 2 # -} 'в верхней части файла? Я думаю, что это должно сработать, но я хочу быть уверенным, прежде чем написать ответ. – Vitus
Хм. Между тем, разместив этот вопрос и прочитав ответ, я перешел на Agda 2.3.3. Теперь решение 'unionWith' работает, без каких-либо явных настроек' --termination-depth'. Я отправлю это в качестве ответа для дальнейшего использования. К сожалению, мне нелегко вернуться к 2.3.2, поэтому я не могу провести эксперимент '--termination-depth = 2'. Извините за это (особенно, поскольку я сказал, что хочу избежать установки версии разработки). – Roly
Да, я заметил, что второе решение работает в версии разработки. Новые функции в 2.3.3 сделали «-версию-глубину» бесполезной; теперь он включен «по умолчанию» (средство проверки окончания работает так, как если бы «--termination-depth = бесконечность», если я правильно понял заметки о выпуске), поэтому мой первый инстинкт заключался в том, чтобы попытаться явно установить «-терминацию-глубину» в более ранняя версия. У меня была версия разработки с ноября, которая, как я думаю, не имеет нового алгоритма, и, похоже, она работает там. – Vitus