Types Agda:形成所有对{(x,y)| x in xs,y in ys}

Types Agda:形成所有对{(x,y)| x in xs,y in ys},types,functional-programming,agda,theorem-proving,dependent-type,Types,Functional Programming,Agda,Theorem Proving,Dependent Type,我想知道在Agda中实现列表理解或笛卡尔积的最佳方法是什么 我有两个向量,xs和ys。我想要(非正式的)集合{(x,y)| x in xs,y in 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 -

我想知道在Agda中实现列表理解或笛卡尔积的最佳方法是什么

我有两个向量,
xs
ys
。我想要(非正式的)集合{(x,y)| x in xs,y in 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
我不知道如何构造这样一个证人。据我所知,我失去了太多的向量的原始结构,无法使用归纳法

我在想

  • 在标准库中是否有处理这种“所有对”操作的东西,已经证明了引理是这样的
  • 如果没有,我该如何着手构建配对证人
  • 我上传了所有正确的导入,使您更容易使用代码

    这里重要的是查看运行
    allPairs
    时获得的最终向量的结构:获得具有精确模式的
    m
    大小
    n

    • 第一个区块列出了由
      xv
      的头部以及
      yv
      中的每个元素组成的对

    • (……)

    • 第n块列出了由
      xv
      的第n个元素以及
      yv
      中的每个元素组成的对

    所有这些块都是通过连接(
    \uu++\uu
    )来组装的。为了能够选择一个块(因为您要查找的
    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
    

    另一种方法是将证据分成两部分。第一部分是
    x∈ xs->y∈ ys->(x,y)∈²xs×ys
    ,其中
    返回矩阵而不是向量。第二个是
    x∈²xss->x∈ concat xss
    。两者都
    _∈_
    _∈²
    可以用
    任何
    来表示,因此我认为还有进一步推广的余地。如果我在写一个库,我会选择这种方法,但对于简单的练习来说,这可能有些过头了。顺便说一句,解析包含ASCII符号序列的mixfix运算符并非易事,比如
    xs
    in
    _∈map_xs
    。我有点困惑。。。问题是什么∈ 在“有”的情况下两两如何?我以为它是一个类型构造函数,所以在值位置看到它时我很困惑。它来自这个mixfix标识符:
    _∈_++ys
    。我试着给引理命名,强调它们正在做的事情,但是由于在SO中没有语法突出显示,所以很难阅读。我建议下载要点并在emacs中查看。如果你愿意,我也可以用重命名的引理编辑我的答案。