【发布时间】:2014-01-09 09:36:27
【问题描述】:
我想对比两种在 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、Semigroup、Monoid 和 @987654328 @ 在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 的字段复制到BoundedJoinSemilattice 中,而是让后者声明一个CommutativeMonoid 类型的字段。然后我们使用open...public 将其子字段“继承”到包含记录中。确实,这正是标准库 Algebra.Structures 中其他地方使用的惯用语,只是这里我们还重命名了继承的字段,以便在继承上下文中适当地命名它们。
这第二种方法不仅冗余更少,而且现在想要从CommutativeMonoid 构造BoundedJoinSemilattice 的客户端代码可以简单地将其作为参数传递给正在构造的记录。另一方面,想要从头构造BoundedJoinSemilattice 的客户端代码现在必须构造一个中间CommutativeMonoid。
Algebra 模块不使用这种继承风格,而Algebra.Structures 使用这种继承风格有什么原因吗?也许第二种方法存在我没有发现的问题,或者它没有太大区别:例如,对于第一种方法,也许可以简单地定义一个“构造函数”来处理 @987654346 的构造@来自CommutativeMonoid,以恢复第二种方法的大部分便利。
【问题讨论】:
标签: inheritance record agda