Skill 语言语法基础

1 Skill 的语言特征

Skill 是一门高级交互编程语言,基于 Lisp 语言开发,同时也支持类 C 语言语法,但是不建议使用类 C 风格写法,有些地方用 C 风格的很别捏。发展至今,Skill 不仅支持函数式编程,还支持命令式编程,而且面向对象编程也是作了支持。

1.1 程序即数据

这是 Skill 最重要的一个特征,在 Skill 中程序和数据一样被表示为列表,所以它们就像数据一样可以被操作。我们可以动态地创建或修改列表,比如一个函数可以反复被重定义,进而影响到使用这个函数的地方,这种"程序即数据"的概念使得 Skill 可以用来编写灵活的应用程序。

1.2 Skill 的表达式

既然程序即数据,那它们就一定得有共同的表示形式,在 Skill 中也称作 S 表达式,有两种:

  • 原子

原子是一个单独的值,可以是数字、字符串、符号等,比如

ini 复制代码
123         ;数字
"hello"     ;字符串
Symbol      ;符号
  • 列表

列表是由一对圆括号包围的一系列表达式,其中第一个元素通常是函数或宏的名字,后面的元素是函数的参数。列表元素间用空格隔开。列表可以彼此嵌套使用,这也是 Skill 灵活语法的直观体现。

scss 复制代码
(list 1 2 3)        ; 创建列表 (1 2 3)
(cons 1 (list 2 3)) ; 创建列表 (1 2 3)

在上面这段代码里,list 是一个函数名称,用于创建列表;cons 也是一个函数,用来连接两个列表。

1.3 Skill 的函数调用

在 Skill 中可以像 C 语言那样调用函数,也可以使用 Skill 的 S 表达式形式。例如现在有一个函数 add,接收两个数字返回相加后的结果。

  • C语言风格
scss 复制代码
 add(1 5)  ; 返回6  
  • S 表达式风格
csharp 复制代码
(add 1 5)    ; 返回6

Skill 中,函数默认返回函数体中最后一个表达式的值,如果最后一个表达式无返回值,则返回 nil,nil 表示空值。

2 特殊符号

Skill 中有一些符合具有特殊函数,且不同于常见的语言(如 C 和 Java)。

2.1 括号 ()

在 Skill 中括号代表一个列表表达式,要求第一个参数是函数,所以不能像在 C 语言里面那样随意加。如下图所示,我们给数字 1 加括号,就会报错。

给数字 1 加括号

如果想使用括号定义列表,除了使用 list 函数外,还可以使用单引号 '。

scss 复制代码
'(1 2 3)    ; 创建列表 (1 2 3)

2.2 单引号 '

Skill 中的单引号有使用原本值的意思,类似于引用的感觉。可用于创建列表及创建符号变量以及引用函数。比如

ini 复制代码
'a    ; 创建符合 a
'abc  ; 创建符合 abc
(fboundp 'add)  ; 这里的单引号就是引用函数 add 的意思

2.3 分号 ;

分号用于单行注释,我在之前已经有使用过,多行注释的形式则跟其他语言类似,使用 /* ... */ 的形式。

2.4 空格

空格用于Skill 中的元素分割。

2.5 大括号 {}

大括号把多个表达式组合成一个表达式,返回值是最后一个表达式的返回值,可以减少不必要的返回值。如图所示,下面的代码只有一个返回值 5。

大括号的使用

2.6 t

t 表示布尔值 true,false 使用 nil。此外,所有的非 nil 值都会被认为是 true,尤其要注意 0 也是 true,这与 C++ 中很不同。

2.7 中括号 []

中括号用于数组的下标访问。

3 变量及变量类型

前文我们多次提到符号、变量之类的词,这里就说说 Skill 中的变量。

变量在 Skill 中叫做 Symbol,是动态类型,使用前不需要先声明,跟 python 很像。

Skill 中的变量默认是全局变量,局部变量需要特别声明,尤其要注意这点,否则很容易改变全局变量的值,造成逻辑错误。

3.1 变量类型

  • 符号 symbol

symbol 既是刚刚说到的变量,又代表一种数据类型,类似 char 类型的变量。

第一次 a 的类型是 symbol

  • 字符串 string

是的,就是我们熟知的字符串,无需多言。

  • 整数 integer

整数。

  • 浮点数 float

浮点数。

  • 列表 list

列表是一种数据结构,也可以说是一种变量类型,这里我们就傻傻不分清,在 Skill 中连程序都是数据,数据结构其实没那么严格。

使用 list 函数或者单引号创建列表。列表对元素个数、元素类型没有限制,可以任意嵌套。要注意,使用单引号定义 list 时,不会对内部的表达式进行展开求值。

使用单引号 ' 定义list

还可以使用冒号定义只有两个元素的 list,常用于定义坐标。

ini 复制代码
 a = ( 1 : 4 )    ;定义列表 (1 4)
  • 数组 array

使用 declare 定义数组:

ini 复制代码
(declare week[7])    ; 定义一个含7个元素的数组

数组元素使用 [] 的形式进行访问,下标从 0 开始。数组可以直接使用等会赋值,是浅拷贝。

  • 关联表 Association Tables

以 key/value 的形式保存的数据的集合,key 的类型没有限制,可以是任意类型。使用 makeTable 函数创建一个table:

ini 复制代码
myTable = (makeTable "table1" 0)

"table1"是表名,并不是变量名称,0 表示从表中查不到 key 时返回 0。

3.2 局部变量

  • 使用 let 定义局部变量

不声明初始值的格式如下,定义了 a,b 两个局部变量。

使用 let 定义局部变量

声明初始值的格式,如下,局部变量 a 的初始值是 7,b 的初始值是 5.

使用 let 定义局部变量并赋初始值

  • 使用 prog 定义局部变量

prog 增加了对 return 和 go 的支持,要注意,prog 和 循环一起使用时,return 始终是返回到 prog 的外围,prog 没有赋初始值的语法。

3.3 局部变量的特性

局部变量能穿透到函数内部,就跟全局变量一样。

下图定义了两个函数 trOne 和 trTwo,trOne 先定义了局部变量 aGlobal 然后调用了函数 trTwo;trTwo 函数第一行会打印 aGlobal 的值。

局部变量穿透到函数内部

如果我们调用 trOne,发现内部的 trTwo 函数里第一行的 aGlobal 是 trOne 里定义的局部变量,值为 5;如果我们在 trOne 外面直接调用 trTwo,此时访问的是全局变量 aGlobal。

相关推荐
Asthenia04121 小时前
Spring扩展点与工具类获取容器Bean-基于ApplicationContextAware实现非IOC容器中调用IOC的Bean
后端
bobz9651 小时前
ovs patch port 对比 veth pair
后端
Asthenia04121 小时前
Java受检异常与非受检异常分析
后端
uhakadotcom2 小时前
快速开始使用 n8n
后端·面试·github
JavaGuide2 小时前
公司来的新人用字符串存储日期,被组长怒怼了...
后端·mysql
bobz9652 小时前
qemu 网络使用基础
后端
Asthenia04122 小时前
面试攻略:如何应对 Spring 启动流程的层层追问
后端
Asthenia04123 小时前
Spring 启动流程:比喻表达
后端
Asthenia04123 小时前
Spring 启动流程分析-含时序图
后端
ONE_Gua3 小时前
chromium魔改——CDP(Chrome DevTools Protocol)检测01
前端·后端·爬虫