假设我有一个值x : A
,我想定义一个只包含x
的集合。
这就是我的尝试:
open import Data.Product
open import Relation.Binary.PropositionalEquality
-- Singleton x is the set that only contains x. Its values are tuples containing
-- a value of type A and a proof that this value is equal to x.
Singleton : ∀ {ℓ} {A : Set ℓ} → (x : A) → Set ℓ
Singleton {A = A} x = Σ[ y ∈ A ] (y ≡ x)
-- injection
singleton : ∀ {ℓ} {A : Set ℓ} → (x : A) → Singleton x
singleton x = x , refl
-- projection
fromSingleton : ∀ {ℓ} {A : Set ℓ} {x : A} → Singleton x → A
fromSingleton s = proj₁ s
有更好的方法吗?
我想要这个的例子:如果你在某个集合A上有一个幺半群,那么你可以形成一个以A作为唯一对象的类别。要在Agda中表达,您需要一种方法来编写“仅包含A的集合”。
答案 0 :(得分:4)
我认为这是一个非常好的方法。通常,当您想要创建类型的“子集”时,它看起来像:
postulate
A : Set
P : A → Set
record Subset : Set where
field
value : A
prop : P value
但是,这可能不是一个子集,因为它实际上可以包含比原始类型更多的元素。这是因为prop
可能有更多命题不同的值。例如:
open import Data.Nat
data ℕ-prop : ℕ → Set where
c1 : ∀ n → ℕ-prop n
c2 : ∀ n → ℕ-prop n
record ℕ-Subset : Set where
field
value : ℕ
prop : ℕ-prop value
突然,子集的元素数量是原始类型的两倍。我同意这个例子有点人为,但想象你在集合上有一个子集关系(集合理论的集合)。这样的事情实际上是相当可能的:
sub₁ : {1, 2} ⊆ {1, 2, 3, 4}
sub₁ = drop 3 (drop 4 same)
sub₂ : {1, 2} ⊆ {1, 2, 3, 4}
sub₂ = drop 4 (drop 3 same)
解决此问题的常用方法是使用不相关的参数:
record Subset : Set where
field
value : A
.prop : P value
这意味着类型Subset
的两个值相等,如果它们具有相同的value
,则prop
字段与无关。事实上:
record Subset : Set where
constructor sub
field
value : A
.prop : P value
prop-irr : ∀ {a b} {p : P a} {q : P b} →
a ≡ b → sub a p ≡ sub b q
prop-irr refl = refl
然而,这更像是一个指导原则,因为你的代表不会遇到这个问题。这是因为在Agda中实现模式匹配意味着 axiom K :
K : ∀ {a p} {A : Set a} (x : A) (P : x ≡ x → Set p) (h : x ≡ x) →
P refl → P h
K x P refl p = p
嗯,这并没有告诉你多少。幸运的是,还有另一个属于公理K的属性:
uip : ∀ {a} {A : Set a} {x y : A} (p q : x ≡ y) → p ≡ q
uip refl refl = refl
这告诉我们,只有一种方法可以使两个元素相等,即refl
(uip
表示身份证明的唯一性)。
这意味着当你使用命题相等来制作一个子集时,你就得到了一个真正的子集。
让我们明确指出:
isSingleton : ∀ {ℓ} → Set ℓ → Set _
isSingleton A = Σ[ x ∈ A ] (∀ y → x ≡ y)
isSingleton A
表示A
只包含一个元素,直到提议性相等。事实上,Singleton x
是一个单身人士:
Singleton-isSingleton : ∀ {ℓ} {A : Set ℓ} (x : A) →
isSingleton (Singleton x)
Singleton-isSingleton x = (x , refl) , λ {(.x , refl) → refl}
有趣的是,这也可以在没有公理K的情况下工作。如果你将{-# OPTIONS --without-K #-}
pragma放在文件的顶部,它仍然会编译。
答案 1 :(得分:1)
您可以定义没有投影的记录:
record Singleton {α} {A : Set α} (x : A) : Set α where
fromSingleton : ∀ {α} {A : Set α} {x : A} -> Singleton x -> A
fromSingleton {x = x} _ = x
singleton : ∀ {α} {A : Set α} -> (x : A) -> Singleton x
singleton _ = _
或等同
record Singleton {α} {A : Set α} (x : A) : Set α where
fromSingleton = x
open Singleton public
singleton : ∀ {α} {A : Set α} -> (x : A) -> Singleton x
singleton _ = _
现在您可以像这样使用它:
open import Relation.Binary.PropositionalEquality
open import Data.Nat
f : Singleton 5 -> ℕ
f x = fromSingleton x
test : f (singleton 5) ≡ 5
test = refl
test' : f _ ≡ 5
test' = refl
这被拒绝了:
fail : f (singleton 4) ≡ 4
fail = ?
错误:
4 != 5 of type ℕ
when checking that the expression singleton 4 has type Singleton 5
答案 2 :(得分:1)
可以将其定义为indexed datatype:
data Singleton {ℓ : _} {A : Set ℓ} : A -> Set where
singleton : (a : A) -> Singleton a
这类似于命题平等a ≡ b
如何被两个特定元素a
和b
编入索引,或者Vector X n
如何被特定n ∈ ℕ
编入索引