我想对比两种在 Agda 中为代数结构声明新记录类型的风格。
按照标准 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
、和。为了将 a视为其“超类型”之一,必须调用一个投影函数,该函数负责将其字段映射到超类型的字段,例如上面的函数。Semigroup
Monoid
CommutativeMonoid
BoundedJoinSemiLattice
BoundedJoinSemiLattice
commutativeMonoid
但是,这种字段重复可能会导致代码中出现大量样板,这些样板会从不太具体的代数结构中构建出更具体的代数结构。更自然的定义可能是这样的(重命名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
into的字段BoundedJoinSemilattice
,而是让后者声明一个 type 的字段CommutativeMonoid
。然后我们使用 anopen...public
将其子字段“继承”到包含记录中。事实上,这正是标准库中其他地方使用的惯用语Algebra.Structures
,除了这里我们还重命名了继承的字段,以便在继承上下文中适当地命名它们。
第二种方法不仅不那么冗余,而且现在想要BoundedJoinSemilattice
从 a构造 a 的客户端代码CommutativeMonoid
可以简单地将其作为参数传递给正在构造的记录。另一方面,想要BoundedJoinSemilattice
从头构造 a 的客户端代码现在必须构造一个中间CommutativeMonoid
.
Algebra
模块不使用这种继承风格 是有原因的Algebra.Structures
吗?也许第二种方法存在我没有发现的问题,或者它没有太大区别:例如,对于第一种方法,也许可以简单地定义一个“构造函数”来处理BoundedJoinSemiLattice
从 a 构造 a CommutativeMonoid
,恢复了第二种方法的很多便利。