简体   繁体   English

Agda 模式如何与相同类型的构造函数匹配?

[英]How does agda pattern match with same typed constructors?

I have started working my way through the Programming Language Foundations in Agda book and have become confused while attempting to perform the exercise which asks you to write an inc function which increments a binary number represented by the following Bin type:我已经开始研究Agda 中的 Programming Language Foundations书,并且在尝试执行要求您编写inc function 的练习时感到困惑,该练习会增加由以下Bin类型表示的二进制数:

data Bin : Set where
  ⟨⟩ : Bin
  _O : Bin → Bin
  _I : Bin → Bin

I started writing my inc function as我开始将我的inc function 写为

inc_ : Bin → Bin
inc ⟨⟩ = ⟨⟩
inc (x O) = {!!}
inc (x I) = {!!}

and then thought: "How does Agda know if a value of type Bin can be matched and destructed into x O and x I without ambiguity if the _O and _I constructors have the same type?".然后想:“如果_O_I构造函数具有相同的类型,Agda 怎么知道Bin类型的值是否可以匹配并分解为x Ox I而没有歧义?”。 The more I thought about this the more confused I became, if we take the Nat example:如果我们以Nat为例,我越想越困惑:

data ℕ : Set where
  zero : ℕ
  succ : ℕ → ℕ

the zero and succ constructors both produce a value of type , so how does Agda know whether some particular value of type would match the patterns I have in place for functions such as _+_ ? zerosucc构造函数都产生类型的值,那么 Agda 如何知道类型的某些特定值是否与我为_+_等函数设置的模式匹配?

_+_ : ℕ → ℕ → ℕ
zero + m = m
succ n-1 + m = succ (n-1 + m)

It seems to me the only way this could work is if Agda keeps track of the constructor used to create each value, and then allows for using that same constructor in pattern matching?在我看来,唯一可行的方法是,如果 Agda 跟踪用于创建每个值的构造函数,然后允许在模式匹配中使用相同的构造函数?

I am very new to Agda and trying to wrap my head around the relationship between types, values, constructors and pattern matching.我对 Agda 很陌生,并试图围绕类型、值、构造函数和模式匹配之间的关系展开思考。 I would very much appreciate an explanation of how these relate with reference to the Bin and examples in my question.我非常感谢您参考我的问题中的Bin示例来解释这些之间的关系。 I have tried reading some additional articles/books/lecture sides and the Agda docs but I could not find an answer to this question.我已经尝试阅读一些额外的文章/书籍/讲座和 Agda 文档,但我找不到这个问题的答案。

This issue first arises with a very simple type – the Booleans:这个问题首先出现在一个非常简单的类型——布尔值:

data Bool : Set where
  true : Bool
  false : Bool

We can write functions out of Bool by pattern matching, for example:我们可以通过模式匹配从Bool中写出函数,例如:

not : Bool → Bool
not true = false
not false = true

Bool , like similar types in other programming languages, is a type with two canonical inhabitants: true and false . Bool与其他编程语言中的类似类型一样,是具有两个规范居民的类型: truefalse A Bool value stores 1 bit of information.一个Bool值存储 1 位信息。 At run time, and also for the sake of computation at type checking time, we could imagine that there literally is a bit in the specified memory location indicating whether the value is true or false .在运行时,也为了在类型检查时进行计算,我们可以想象在指定的 memory 位置中有一个位指示该值是true还是false

In terms of data declarations, this bit comes about because Bool has two constructors.data声明方面,这个位的出现是因为Bool有两个构造函数。 Similarly, has two constructors, so that will also contain a bit indicating whether the value is a zero or suc (and if it is a suc , there will also be a pointer to the rest of the number).同样, 有两个构造函数,因此它还将包含一个位,指示该值是zero还是suc (如果是suc ,还将有一个指向数字的 rest 的指针)。 For Bin , we will store a 0, 1, or 2, to indicate whether we have a ⟨⟩ , _O , or _I .对于Bin ,我们将存储 0、1 或 2,以指示我们是否有⟨⟩_O_I

It is this extra information (one or two bits for the examples here) that pattern matching relies on.模式匹配所依赖的正是这些额外信息(此处的示例为一个或两个位)。 In fact, types are typically erased, so pattern matching couldn't use them.事实上,类型通常会被删除,因此模式匹配无法使用它们。 As such, not is essentially compiled to something like the following pseudo-C.因此, not本质上被编译为类似于以下伪 C 的东西。

int* not(int* b) {
  switch (*b) {                    // Look at the tag of b.
    case 0:                          // If b is true,
      int* r = malloc(sizeof(int));    // Allocate a new boolean;
      *r = 1;                          // Set the value of the new boolean to false;
      return r;                        // Return the new boolean.
    case 1:                          // If b is false,
      int* r = malloc(sizeof(int));    // Allocate a new boolean;
      *r = 0;                          // Set the value of the new boolean to false;
      return r;                        // Return the new boolean.
  }
}

Meanwhile, the _+_ function on will be compiled into something like:同时, 上的_+_ function 将被编译成如下内容:

int* add(int* n, int* m) {
  switch (*n) {                        // Look at the tag of n.
    case 0:                              // If n is zero,
      return m;                            // Return m.
    case 1:                              // If n is a suc,
      int* r = malloc(2 * sizeof(int));    // Allocate space for a suc cell;
      *r = 1;                              // Indicate that it is a suc by setting the tag to 1;
      *(r+1) = add(n+1, m);              // After the tag is a pointer, set to the result of the recursive call to add.
      return r;                            // Return the new ℕ.
  }
}

Note that n+1 here refers to the memory location after n 's tag, ie, the pointer to the predecessor of n ( n-1 in the Agda code).注意这里的n+1是指n的tag后面的memory位置,即指向n的前身的指针(Agda代码中的n-1 )。 I'm assuming for simplicity that sizeof(int) = sizeof(int*) , and it's fine to store pointers in the int type.为简单起见,我假设sizeof(int) = sizeof(int*) ,并且可以将指针存储在int类型中。 The key detail is that we always tag data values with which constructor they are made of, and having done this, branching via pattern matching amounts to looking at this tag.关键细节是我们总是用它们构成的构造函数来标记data值,并且这样做之后,通过模式匹配进行分支相当于查看这个标记。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 模式匹配专门的构造函数 - Pattern match on specialised constructors 如何创建为参数类型字段创建默认值的构造函数 - How to make constructors that create default values for the parametrically typed fields Agda:模式匹配相等的变量? - Agda: pattern matching equal variables? 如何理解 agda 中的数据与记录功能? - How does one understand Data vs Record capabilities in agda? 尽管有模式匹配,但 Agda 并未消除目标中的子句 - Agda not eliminating clause in goal despite pattern matching on it 强类型枚举作为 rust 中的联合:如何确定值的类型并检索它; 如何做“构造函数” - Strongly typed enum as union in rust: How to determine type of value and retrieve it; How to do "constructors" 如何比较阿格达的Nats向量 - How to compare Vectors of Nats in Agda 一个人如何编写(和调试)一个依赖于两个参数的应用程序 apd2,并使用它来证明这种 ap 在 agda 中的功能性? - How does one write (and debug) a two arguement dependent application, apd2, and use this to prove functoriality of such ap in agda? 在 Agda 中的同一 Γ 内形式化多个类型判断 ⊢ - Formalizing multiple type judgements ⊢ within the same Γ in Agda 自定义构造函数 Haskell 上的模式匹配 - Pattern matching on custom constructors Haskell
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM