我想知道在Agda中处理列表推导或笛卡尔产品的最佳方法是什么。
我所拥有的是两个向量,xs
和ys
。我想要(非正式)集合{(x,y)| x在xs中,y在ys中。
我可以使用map和concat很容易地形成这个集合:
allPairs : {A : Set} -> {m n : ℕ} -> Vec A m -> Vec A n -> Vec (A × A) (m * n)
allPairs xs ys = Data.Vec.concat (Data.Vec.map (λ x -> Data.Vec.map (λ y -> (x , y) ) ys ) xs )
从这里开始,我喜欢为双人作见证,比如:
pairWitness : ∀ {A} -> {m n : ℕ} -> (xv : Vec A m) -> (yv : Vec A n) -> (x : A) -> (y : A) -> x ∈ xv -> y ∈ yv -> (x , y ) ∈ allPairs xv yv
我不知道如何建造这样的证人。据我所知,我失去了太多的矢量原始结构,以便能够使用我的归纳案例。
我想知道
答案 0 :(得分:4)
我已使用所有正确的导入上传a self-contained version of the code,以便您更轻松地使用代码。
这里重要的是查看运行allPairs
时获得的最终向量的结构:您获得具有精确模式的m
大小为n
的块。< / p>
第一个块列出由xv
的头部组成的对以及yv
中的每个元素。
(...)
第n个块列出了由xv
的第n个元素组成的对以及yv
中的每个元素。
所有这些块都是通过连接(_++_
)组装的。为了能够选择一个块(因为你要查找的x
)或跳过它(因为x
更远),你将引入中间体描述_++_
和_∈_
之间相互作用的定理。
你应该能够知道如何选择一个块(如果x
在这个中),这对应于这个简单的中间引理:
_∈xs++_ : {A : Set} {x : A} {m : ℕ} {xs : Vec A m}
(prx : x ∈ xs) {n : ℕ} (ys : Vec A n) → x ∈ xs ++ ys
here ∈xs++ ys = here
there pr ∈xs++ ys = there (pr ∈xs++ ys)
但是你也应该能够跳过一个块(如果x
离得更远),这对应于另一个引理:
_∈_++ys : {A : Set} {x : A} {n : ℕ} {ys : Vec A n}
(prx : x ∈ ys) {m : ℕ} (xs : Vec A m) → x ∈ xs ++ ys
pr ∈ [] ++ys = pr
pr ∈ x ∷ xs ++ys = there (pr ∈ xs ++ys)
最后,一旦选择了正确的块,您可以注意到它是使用map
创建的,如下所示:Vec.map (λ y -> (x , y)) ys
。好吧,您可以证明的一点是map
与会员证明兼容:
_∈map_xs : {A B : Set} {x : A} {m : ℕ} {xs : Vec A m}
(prx : x ∈ xs) (f : A → B) → f x ∈ Vec.map f xs
here ∈map f xs = here
there pr ∈map f xs = there (pr ∈map f xs)
现在,您可以将所有这些放在一起,并通过感应来证明x ∈ xs
:
pairWitness : {A : Set} {m n : ℕ} (xv : Vec A m) (yv : Vec A n)
{x y : A} -> x ∈ xv -> y ∈ yv -> (x , y) ∈ allPairs xv yv
pairWitness (x ∷ xv) yv here pry = pry ∈map (λ y → x , y) xs ∈xs++ allPairs xv yv
pairWitness (x ∷ xv) yv (there prx) pry = pairWitness _ _ prx pry ∈ Vec.map (λ y → x , y) yv ++ys