我想對比兩種樣式來爲Agda中的代數結構聲明新的記錄類型。爲代數結構聲明記錄類型的推薦約定
繼標準阿格達包Algebra
使用的樣式,人們可以如下定義BoundedJoinSemilattice
:
record IsBoundedJoinSemilattice {a ℓ} {A : Set a}
(_≈_ : Rel A ℓ) (_∨_ : Op₂ A) (⊥ : A) : Set (a Level.⊔ ℓ) where
field
isCommutativeMonoid : IsCommutativeMonoid _≈_ _∨_ ⊥
idem : Idempotent _≈_ _∨_
open IsCommutativeMonoid isCommutativeMonoid public
record BoundedJoinSemilattice c ℓ : Set (suc (c ⊔ ℓ)) where
infixr 6 _∨_
infix 4 _≈_
field
Carrier : Set c
_≈_ : Rel Carrier ℓ
_∨_ : Op₂ Carrier
⊥ : Carrier
isBoundedJoinSemilattice : IsBoundedJoinSemilattice _≈_ _∨_ ⊥
open IsBoundedJoinSemilattice isBoundedJoinSemilattice public
commutativeMonoid : CommutativeMonoid _ _
commutativeMonoid = record {
Carrier = Carrier;
_≈_ = _≈_;
_∙_ = _∨_;
ε = ⊥;
isCommutativeMonoid = isCommutativeMonoid
}
採用這種方法的BoundedJoinSemiLattice
是重疊(最多重命名)與其他任何領域更抽象的結構如Setoid
,Semigroup
,Monoid
和CommutativeMonoid
是重複在BoundedJoinSemiLattice
。爲了將BoundedJoinSemiLattice
作爲它的「超類型」之一來查看,必須調用投影函數來負責將其字段映射到超類型的字段,例如上面的函數。
但是,這種字段重複可能會導致代碼中的重要樣板文件,這些代碼構建更具體的代數結構。而更自然的定義可能是這樣的(重命名CommutativeMonoid
到CM
):
record IsBoundedJoinSemilattice {c ℓ} (cm : CM c ℓ)
(⊥ : CM.Carrier cm) : Set (c Level.⊔ ℓ) where
field
isCommutativeMonoid : IsCM (CM._≈_ cm) (CM._∙_ cm) ⊥
idem : Idempotent (CM._≈_ cm) (CM._∙_ cm)
open IsCommutativeMonoid isCommutativeMonoid public
record BoundedJoinSemilattice c ℓ : Set (suc (c ⊔ ℓ)) where
field
commutativeMonoid : CM c ℓ
isBoundedJoinSemilattice : IsBoundedJoinSemilattice commutativeMonoid (CM.ε commutativeMonoid)
open CommutativeMonoid commutativeMonoid public using (Carrier; _≈_) renaming (
_∙_ to _∨_;
ε to ⊥
)
open IsBoundedJoinSemilattice isBoundedJoinSemilattice public
這裏,想法是不重複的CommutativeMonoid
領域爲BoundedJoinSemilattice
,而後者申報類型的單場CommutativeMonoid
。然後,我們使用open...public
將其子字段「繼承」到包含的記錄中。事實上,這正是Algebra.Structures
中標準庫中其他地方使用的成語,除了這裏我們也重命名了繼承的字段,以便它們在繼承上下文中被適當地命名。
這不僅是第二種方法不那麼多餘,但是現在想要從CommutativeMonoid
構造一個BoundedJoinSemilattice
的客戶端代碼可以簡單地將它作爲參數傳遞給正在構建的記錄。另一方面,想要從零開始構建BoundedJoinSemilattice
的客戶端代碼現在必須構建中間CommutativeMonoid
。
是否有一個原因Algebra
模塊不使用這種繼承風格,但Algebra.Structures
呢?也許第二種方法存在問題,我還沒有發現,或者它沒有太大的區別:例如,第一種方法,也許可以簡單地定義一個「構造函數」函數,它可以處理構建BoundedJoinSemiLattice
一個CommutativeMonoid
,以恢復第二種方法的許多便利。
再次感謝您的出色答案。是的,攜帶(並且必須依賴)證明兩個承運人是平等的(例如)聽起來很混亂。這主要是由於記錄類型的存在性?我遇到了一個類似的問題,試圖爲一個數據類型嘗試實現'Functor',而不是一個'IsCommutativeMonoid'提供的交換monoid - 我沒有辦法獲得'Set →爲'Functor'實例設置',因爲載體被埋在'CommutativeMonoid'中。 – Roly
無論如何,你的'semigroup→monoid'函數是我試圖避免的樣板的一個例子,但與'subst'相比,它看起來無害。更重要的是,你的第二個版本的isSemigroup引入了一個我不知道的Agda特性,這幾乎使得樣板問題消失了:) 最後,我還了解到我可以放一個'let ...在函數簽名裏面!好東西,再次感謝。 – Roly
@Roly:是的,有時您只需要通過運營商進行參數化的結構(可能是平等),但操作隱藏在記錄中。問題是你在哪裏畫線?你是否公開承運人+平等並保持其他隱藏?如果結構有多個關係(例如某些部分順序),或者如果您需要通過該操作進行參數化,該怎麼辦?我認爲圖書館給出了一個公平的選擇:明確的,更細化的定義('IsSomething')和通常的數學定義(一組操作)。 – Vitus