K语言入门学习2:第一个程序

这堂课将主要讲解K语言中的关于生产(productions)和规则的基础知识。

  1. 生产和规则是K语言中两种语句类型。
  2. 一个K文件由一个或多个requires或模块组成。
  3. 一个模块又由一个或多个imports或语句组成。

这堂课先不会过多解释requires,模块(modules),和语句(sentences)等的概念;只要先把模块当作语句的一个容器就好,在下面的学习中,还不用太纠结requires或imports是什么,有什么区别与 联系等。

第1个K程序

在notepad++中创建文件:lesson-02-a.k,这个文件的内容如下:

module LESSON-02-A

  syntax Color ::= Yellow() | Blue()
  syntax Fruit ::= Banana() | Blueberry()
  syntax Color ::= colorOf(Fruit) [function]

  rule colorOf(Banana()) => Yellow()
  rule colorOf(Blueberry()) => Blue()

endmodule

执行下面命令来编译这个文件

kompile lesson-02-a.k

其中kompile是K的编译器。上面的命令,会得到一个解释器(interpreter )。
在这里插入图片描述

  1. 从上图,可以看到,编译创建目录 lesson-02-a-kompiled来存放编译的结果。

  2. 虽然这个例子里只有一个K文件,在实际项目中可能会多个K文件,它们编译后会合成一个K定义(K definition);具体什么是K定义,我们后面会讲。
    在这里插入图片描述

  3. 在这个编译产生的目录里,包含基于定义来执行程序,或完成证明的所有东西。

下面我们在文件lesson-02-a.k所在的目录下,创建文件banana.color,并在该文件中输入以下内容:

colorOf(Banana())

然后,可以通过执行以下的命令,来评估这条短语:

krun banana.color

该命令输出如下:

在这里插入图片描述

上述krun命令其实会调用kompile编译产生的解释器,来执行banana.color中的短语指令。

你也可以直接用命令行的方式,来指定要执行的指令:

krun -cPGM='colorOf(Banana())'

可以看到,它与指令在文件中情形,输出是一样的:
在这里插入图片描述

生产(Productions)、构造器与函数

下面我们就来看一个程序的源码:

module LESSON-02-B

  syntax Color ::= Yellow()
  syntax Color ::= Blue()
  syntax Fruit ::= Banana()
  syntax Fruit ::= Blueberry()
  syntax Color ::= colorOf(Fruit) [function]

  rule colorOf(Banana()) => Yellow()
  rule colorOf(Blueberry()) => Blue()

endmodule

首先,我们看到该K定义里包含了5个生产:

  • 生产是以关键词syntax开始;
  • 接着是一个sort(分类词),如源码中的Color,Fruit,它们的首字母要大写;
  • 再后而是操作符::=
  • 后面则是一个定义,或更多的生产(productions);生产之间,用操作符|隔开;
  • 生产有多种类型,但在上面的源码中,只牵涉到了两种:
    • 构造器(constructors);
    • 函数(functions)。
  • 操作符|用于具有同样分类(sort)的生产,所以上面的源,基于操作符|,可等效改造如下:
module LESSON-02-C

  syntax Color ::= Yellow()
                 | Blue()
                 | colorOf(Fruit) [function]
  syntax Fruit ::= Banana()
                 | Blueberry()

  rule colorOf(Banana()) => Yellow()
  rule colorOf(Blueberry()) => Blue()

endmodule
  • 所有生产类型都有相似的语法,但上下文(context)和属性(attributes)会有所不同;后面会逐步讲解它们的不同。这里就来看例子中牵涉到知识点:
    • 构造器,像例子的Yellow(), Blue(), Banana(), 以及 Blueberry()就都是构造器,它就像是函数式编程语言中的构造函数,用来构造一个代数数据类型;而这个数据类型,就是操作符::=前面的分类词(sort)所指定;与构造函数一样,该构造器是可以有参数的。
    • 函数,它在后面带有function属性标识它的生产类型;属性都放在生产语句的末尾,由中括号[]括起来;如果有多个属性,则用逗号,区分开来;规则(rules)的属性也是这样设计的。

练习

前面,我们已经试了babana(),有兴趣的同学,可以再用Blueberry()这个生产定义,来检验一下函数colorOf的返回值

规则、匹配与变量

  1. 一条规则(rule)是由rule关键词开始。
  2. 一条规则里至少包含一个重写操作符(rewrite operator)=>
  3. 重写操作符是K语言内在的生产,后面会进一步的讲解;这里我们只要知道,该操作符让一条规则分成了左、右两部分:
  • 左边是函数的名字,以及各式的函数参数;
  • 右边是另一个样式。
  1. 规则的意义相对简单:检测指令解释执行时,会去匹配规则的左半部分;匹配则会输出右半部分;将前面测试的例子,就是匹配到了colorOf(Banana()),所以得到该函数的返回值Yellow()

到这里,我们才讲解一个概念:变量(variable)。初学者容易把它与构造器相混淆。但我们可以从以下几点,来掌握K语言中变量的特性:

  1. 它由一个大写标识符来构成其名字;
  2. 不像构造器具有唯一确定性,一个变量往往可以匹配多种样式(这些样式中包括了一个异常(exception); 因此对于变量,只要名字相同就匹配成功(如果是构造器,则需要内容相同,才算配置成功)。

下面是一个稍微更复杂一点的例子lesson-02-d.k

module LESSON-02-D

  syntax Container ::= Jar(Fruit)
  syntax Fruit ::= Apple() | Pear()

  syntax Fruit ::= contentsOfJar(Container) [function]

  rule contentsOfJar(Jar(F)) => F

endmodule

在这个例子规则中的F,就是一个变量,它将可发匹配Apple(),也可以匹配Pear()。同时也可以通过下面的命令,来检验这个例子的定义:

krun -cPGM='contentsOfJar(Jar(Apple()))'

在这里插入图片描述

执行报错了,那是一个目录下有多个编译产生的K定义所致,我们把lesson-02-a-kompiled目录删除,再试:
在这里插入图片描述

可以看到这次不报错了,输出也与预期相吻合。

最后,我们再补充一个小的知识点:当构造器里的参数有多个时,也是用逗号,隔开。

练习

  1. 扩展lesson-02-a.k中的K定义。加入了黑莓和猕猴桃。为了简单起见,黑莓是黑色的,猕猴桃是绿色的。然后编译定义并测试’ colorOf '函数是否正确处理了这两个新增的水果。
  2. 创建一个新的K定义,将outfit定义为由帽子、衬衫、裤子和鞋子组成的多参数构造函数。定义一个新的分类(sort):Boolean,有两个构造函数:true和false。每顶帽子、衬衫、裤子和鞋子都有一个参数(一种颜色),黑色或白色。然后定义一个outfitMatching 函数,如果服装的所有部分都是相同的颜色,该函数将返回true(你不需要定义返回false的情况)。编写一些测试,检查一下函数的行为是否符合您的预期。

猜你喜欢

转载自blog.csdn.net/DongAoTony/article/details/124656392