Types 专业施工人员的模式匹配

Types 专业施工人员的模式匹配,types,agda,Types,Agda,几天来我一直在为一个问题绞尽脑汁,但我的Agda技能不是很强 我试图在只在特定索引处定义的索引数据类型上编写一个函数。这仅适用于数据构造师的某些专业。我不知道如何定义这样一个函数。我试着把我的问题简化成一个小例子 该设置涉及自然数列表,具有用于见证列表成员的类型和用于删除列表成员的功能 open import Data.Nat open import Relation.Binary.Core data List : Set where nil : List _::_ : (x :

几天来我一直在为一个问题绞尽脑汁,但我的Agda技能不是很强

我试图在只在特定索引处定义的索引数据类型上编写一个函数。这仅适用于数据构造师的某些专业。我不知道如何定义这样一个函数。我试着把我的问题简化成一个小例子

该设置涉及自然数列表,具有用于见证列表成员的类型和用于删除列表成员的功能

open import Data.Nat
open import Relation.Binary.Core

data List : Set where
   nil : List
   _::_ : (x : ℕ) -> (xs : List) -> List

-- membership within a list
data _∈_ (x : ℕ) : List -> Set where 
   here : forall {xs} -> x ∈ (x :: xs)
   there : forall {xs y} -> (mem : x ∈ xs) -> x ∈ (y :: xs) 

-- delete
_\\_ : forall {x} (xs : List) -> (mem : x ∈ xs) -> List
_\\_ nil ()
_\\_ (_ :: xs) here = xs
_\\_ (_ :: nil) (there ()) 
_\\_ (x :: xs) (there p) = x :: (xs \\ p)
只需快速检查删除单例列表的head元素是否为空列表:

check : forall {x} -> nil ≡ ((x :: nil) \\ here)
check = refl
现在我有了一些由列表索引的包装器数据类型

-- Our test data type
data Foo : List -> Set where
  test : Foo nil
  test2 : forall {x} (xs : List) -> (mem : x ∈ xs) -> Foo (xs \\ mem)
test2
构造函数获取一个列表和一个成员值,并根据从列表中删除元素的结果对数据类型进行索引

现在我遇到的问题是我想要一个具有以下特征的函数:

foo : Foo nil -> ℕ
foo = {!!} 
i、 例如,取一个
Foo
值,其索引专门为
nil
。这适用于
测试
情况

foo test = 0
第二种情况很棘手。我最初想象的是:

foo : Foo nil -> ℕ
foo test = 0 
foo (test2 .(_ :: nil) .here) = 1
但Agda抱怨说
xs\\mem!=检查模式test2时,类型列表为nil。(\uz::nil)。这里有类型Foo nil
。因此,我尝试使用带有-子句的

foo : Foo nil -> ℕ
foo test = 0
foo (test2 xs m) with xs \\ m 
... | nil = 1
... | ()
这会产生同样的错误。我已经尝试过各种排列,但遗憾的是,我不太明白如何在模式中使用
n\\m=nil
的信息。我尝试过各种其他类型的谓词,但不太明白如何告诉Agda它需要知道什么。非常感谢您的帮助!谢谢


附加:我在Agda中写了一个证明,在xs
中给出任何
xs:List
m:x\in xs
xs\\m=nil
)意味着
xs=x::nil
m=here
,这似乎对类型检查器有用,但我不确定如何做到这一点。我必须在pi类型上引入一个点式等式,它尊重使问题复杂化的依赖性:

data PiEq {A : Set} {B : A -> Set} : (a : A) -> (b : A) -> (c : B a) -> (d : B b) -> Set where
   pirefl : forall {x : A} {y : B x} -> PiEq {A} {B} x x y y 

check' : forall {x xs m} {eq : xs \\ m ≡ nil} -> (PiEq {List} {\xs -> x ∈ xs} xs (x :: nil) m here)
check' {xs = nil} {()} 
-- The only case that works
check' {xs = ._ :: nil} {here} = pirefl
-- Everything else is refuted
check' {xs = ._ :: (_ :: xs)} {here} {()}
check' {xs = ._ :: nil} {there ()}
check' {xs = ._} {there here} {()}
check' {xs = ._} {there (there m)} {()} 

为什么不定义
foo
by

foo : Foo nil -> ℕ
foo _ = 0
?

注意:使用Agda()的当前开发版本,我得到了错误

I'm not sure if there should be a case for the constructor test2,
because I get stuck when trying to solve the following unification
problems (inferred index ≟ expected index):
  xs \\ mem ≟ nil
when checking the definition of foo
当我写作时

foo test = 0

按照设置数据类型的方式,您无法以任何有意义的方式对具有非平凡索引的值进行模式匹配。问题当然是Agda(通常)无法解决
xs\\mem
nil
的统一

模式匹配的建立方式,不能真正提供任何证据来帮助统一算法。但是,您可以通过不限制索引并使用另一个参数以及描述实际限制的证明来确保模式匹配工作。这样,您可以进行模式匹配,然后使用证明消除不可能的情况

因此,我们将使用另一个带有额外参数的函数(比如
foo-helper
),而不是只有
foo

foo-helper : ∀ {xs} → xs ≡ nil → Foo xs → ℕ
foo-helper  p  test = 0
foo-helper  p  (test2 ys mem) with ys \\ mem
foo-helper  p  (test2 _ _) | nil = 1
foo-helper  () (test2 _ _) | _ :: _
然后,只需提供
nil的证明,就可以恢复原始函数≡ 无

foo : Foo nil → ℕ
foo = foo refl

如果您希望经常进行这种模式匹配,那么最好改为更改数据类型的定义:

data Foo′ : List → Set where
  test′ : Foo′ nil
  test2′ : ∀ {x} xs ys → (mem : x ∈ xs) → ys ≡ xs \\ mem → Foo′ ys
通过这种方式,您可以始终进行模式匹配,因为您没有复杂的索引,并且由于包含的证据,仍然可以消除任何不可能的情况。如果我们想使用此定义编写
foo
,我们甚至不需要帮助函数:

foo′ : Foo′ nil → ℕ
foo′ test′ = 0
foo′ (test2′ xs .nil mem _) with xs \\ mem
foo′ (test2′ _ ._ _ _ ) | nil = 1
foo′ (test2′ _ ._ _ ()) | _ :: _

并表明这两种数据类型(逻辑上)是等价的:

to : ∀ {xs} → Foo xs → Foo′ xs
to test = test′
to (test2 xs mem) = test2′ xs (xs \\ mem) mem refl

from : ∀ {xs} → Foo′ xs → Foo xs
from test′ = test
from (test2′ xs .(xs \\ mem) mem refl) = test2 xs mem

那怎么办?是的。您需要使用
with
子句来确定
test2
案例的类型为
Foo nil
,但是输入必须是
Foo nil
,因此您根本无法访问
with
子句。通过为
Foo
的尾部设置一个变量值,您可以使用
进入
,然后等式确保在
中只有
nil
案例与
有关@Vitus Yes!就是这样!你想把它作为答案贴出来让我接受吗?我以前尝试过类似的方法,但成功地失败了-我想我也在与'refl'的相等性上进行匹配,这使事情变得糟糕,即添加“foo refl rest=0”会引发“我不确定是否应该有构造函数test2的情况”。我觉得这很奇怪!我没有在证据上匹配就没试过!非常抱歉,我的问题有点不清楚。这并不是说我只想要一个常数函数。结果类型ℕ 只是为了演示,但我确实希望每个构造函数得到不同的结果。我对这个问题稍加修改,使之更加清楚。您看到的错误与我的问题有关(当我为“test2”省略一个案例时,我会看到它)。