この質問とこのAgda バグ レポート/機能リクエストで説明されているものと非常によく似た、終了チェックに問題があります。
unionWith
問題は、以下が終了することをコンパイラーに納得させることです。重複キーの結合関数を使用して、unionWith
キーでソートされた (キー、値) ペアのリストとして表される 2 つのマップをマージします。有限マップの Key パラメーターは、マップに含まれるキーの (厳密ではない) 下限です。(このデータ型を定義する理由の 1 つは、AVL ツリーに関するさまざまなプロパティを証明するために 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′)
参照された質問で説明されている解決策を私の設定に一般化することができませんでした。たとえば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
このコンパイルを取得するためにパターンまたは補助関数を使用する方法はありますか? それは簡単な状況のように思えるので、正しいトリックを知っているだけのケースであることを願っています.
(Agda 開発ブランチの新しい終了チェッカーで対処できるかもしれませんが、必要がない限り、開発バージョンのインストールは避けたいと思います。)