14

cora 语言介绍

 4 years ago
source link: https://www.zenlife.tk/cora.md
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

cora 语言介绍

2019-07-22

cora 语言是我设计的一门 lisp 方言。又是一门 lisp?是呀!每个真正的 lisp 程序员都应该发明自己的语言的。。lisp 我一直在学习,关于这门语言我思考了许多年,最终把我喜欢哪些 feature 写下来,也算作是做一个交待吧。

实现一门语言的解释器或者编译器,跟设计一门语言,其实不是同一种乐趣。实现是由别人定好了标准,自己只是按标准做出来。而设计语言的时候,需要了解许许多多语言,知道它们设计背后的思考。然后再决定,哪些 feature 是自己语言里面需要的,哪些是不需要的,这是需要更多审美。另外,用自己设计的语言写东西,是一件非常有成就感的事情

在这里简单介绍一下这门语言。

cora 受到的最主要的影响来自于 scheme 和 shen。当然,考虑到我接触过的那么多语言,也不能排除一些影响来自于其它的项目,比如 femtolisp,比如 ocaml,甚至是 Go。

目前只是做了一个解释器实现,而且代码还非常糙(0.1 版本都没到,迫不急待就来写博客,向世界宣布:hello, world)。代码在这里:https://github.com/tiancaiamao/cora

使用很简单,下载代码,然后 go build 生成 binary。然后 ./cora 就会进入到 repl 了。

闭包是可视化的

这个是 "借鉴" femtolisp 的做法:直接在 lambda 表后面追加环境,环境用的是关联表表示的。

(lambda (x) x) ;; 一个闭包
(lambda (a) 3 (b . 5) (c . 7)) ;; 在 ((b . 5) (c . 7)) 环境下面的闭包

比如执行一下:

➜  cora git:(master) ./cora
1 #> ((lambda (a) (lambda (b) a)) 42)
(lambda (b) a (a . 42))

这么设计,跟 scheme 语法会有冲突,lambda 的 body 只能是单个 expression。如果要多个,就要按这种写法:

(lambda () (begin 1 2 3))

特殊表只有 quote lambda if do macro 等非常少的几个。理论上,macro 也不是一定要做成特殊表的,只不过目前先这么实现着。

所有表达式经过完全的展开后,都会变成最后很少的几个特殊表。因为特殊表是会实现在最核心层的东西,越少越好。

像 defun let defmacro cond list 等等等这些东西都可以做成宏。

0 #> list
(macro exp (rcons (cdr exp)))
1 #> let
(macro exp (rewrite-let () () (cdr exp)))
2 #> or
(macro exp (if (cadr exp) true (caddr exp)))

甚至连 set 都是函数而不是特殊表。

(set 'or (macro exp (list 'if (cadr exp) true (caddr exp))))

我不喜欢括号过多,let 宏是用了更像 shen 那边的表示:

(let a 3 b 5 ...)

这明显比在 scheme 里面的写法要简单:

(let ((a 3) (b 5)) ...)

first class macro

first class macro 并不是一个特意设计的语言特性,只是由于目前是解释器,并且有 macro 特殊表。所以在当前实现中宏是 first class 的。 (macro xxx) 可以传递给变量,可以当作返回值...

8 #> (set 'mylet let)
(macro exp (rewrite-let () () (cdr exp)))
9 #> (mylet a 3 b 5 (+ a b))
8
(defmacro m (exp) body)

实现上仅仅是给变量 m 绑定一个 macro 特殊表。

而到调用 (m xxx) 的时候会先 eval a,发现结果是一个宏,然后使用宏展开,再进行展开之后的 eval。

真正可以算语言设计层面的,是故意采纳了非卫生宏。卫生宏的实现更复杂,而且我感觉属于偏学术而不是真正解决实际问题的特性,因此在 cora 里面没有采用。

严格尾递归

cora 是要求严格尾递归的,这点跟 scheme 强调的一样。这个 feature 成为必须的理由,是来自于我在实现宏的过程中的观察。如果不支持尾递归,在做 pattern match 宏的时候很容易展开后的代码变成非尾递归的,然后爆栈。

比如这么写代码,总不能爆栈吧:

(func f
      0 => 42
      n => (f (- n 1)))
(f 9999999)

partial apply

shen 语言是自动 partial apply 的。我在使用过之后觉得,真香!

自动 partial apply 可以避免很多无用的代码,相比于

(map (lambda (x) (+ x 1)) l)

这样子肯定是更简洁的:

(map (+ 1) l)

在 scheme 里面不必要的重复定义,如果支持 partial apply 就根本不用那么复杂。 本来用宏也可以做一些简化,像 clojure 里面有一些缩写,但是我不太喜欢 sugar 过多。

语言内置 pattern match

pattern match 是一个非常有用的 feature。本来可以做成库的,但是这个重要程度让我觉得,应该由语言内置。

(match (cons 1 2)
  42 42
  's 666
  (cons a b) a
  (list x y z) x
  (list-rest a b) b
  x x)

其实我之前已经提过了,应该 让 pattern 匹配的对象,跟构造这个对象使用的同一种语法

值得一提的是 list-rest。list-rest 是将前面的 pattern 匹配到单个变量,而最后一个变量匹配剩下的链表部分。比如:

3 #> (match (list 1 2 3 4 5 6) (list-rest a b c d) d)
(4 5 6)

这里面 a b c 分别会匹配 1 2 3,而剩下的部分 d 匹配到 (4 5 6)

其它的理解起来都很简单,42 匹配常量;(quote s) 匹配符号 s(cons a b) 匹配一个 cons,(list x y z) 匹配 3 个元素的链表;上面的表达式最后会返回 1。

所有模式都是可组合的,比如这种 (cons (list a 1) 'xx)

func 宏

cora 鼓励优先使用 func 来定义函数。func 是一个宏,这个 syntax 明显是受了 Go 的启发,使用是这样子:

(func filter-h
      res fn () => (reverse res)
      res fn (cons hd tl) => (filter-h (cons hd res) fn tl) where (fn hd)
      res fn (cons _ tl) => (filter-h res fn tl))

=> 前面是模式,匹配函数的输入,后面是执行的操作。可以带 where 过滤条件。

用 pattern match 写出来比 defun 会好读一些。

(defun filter-h (res fn l)
  (if (cons? l)
      (if (fn (car l))
          (filter-h (cons (car l) res) fn (cdr l))
          (filter-h res fn (cdr l)))
      (reverse res)))

好啦,下面才是正经的介绍了:lisp 基础,可以在 cora 里面练习一下。

TL;DR

数字,字符串,布尔的 true 和 false 是常量,常量求值得到自身:

4 #> 1
1
5 #> "asdf"
"asdf"
6 #> true
true
7 #> false
false

quote 特殊表,缩写是单引号 ',被 quote 的东西不求值,可以用它得到符号:

8 #> 'asdf
asdf
9 #> (quote asd)
asd
10 #> (quote (a b c))
(a b c)

变量,在 lambda 或者 let 这些东西里面,参数都是变量:

11 #> (lambda (a) a)
(lambda (a) a)   ;; 这里面的 a
12 #> (let a 3 b 5 (+ a b))  ;; 这个的 a 和 b
8

if 表达式:

13 #> (if true 1 2) 
1

lambda 表达式,也就是定义函数:

17 #> (lambda (x) x)
(lambda (x) x)
18 #> ((lambda (x) x) 42)
42

set 是一个函数,它接受的参数是一个符号和一个值,即设置符号绑定的值:

14 #> (set 'a 3)
3
15 #> (set 'b 5)
5
16 #> (+ a b)
8

注意这个绑定是全局绑定的,跟变量不太一样。定义函数实际上就是为符号,绑定一个 lambda 表达式,比如:

(defun id (x) x)
(set 'id (lambda (x) x))

可以验证一下:

19 #> (defun id (x) x)
(lambda (x) x)
20 #> id
(lambda (x) x)
21 #> (set 'id (lambda (x) x))
(lambda (x) x)
22 #> (id 42)
42

相互递归定义也是可以的

23 #> (defun even (x)
  (if (= x 0)
      true
      (odd (- x 1))))
(lambda (x) (if (= x 0) true (odd (- x 1))))
24 #> (defun odd (x)
  (if (= x 1)
      true
      (even (- x 1))))
(lambda (x) (if (= x 1) true (even (- x 1))))
25 #> (even 30)
true
26 #> (odd 31)
true

Recommend

  • 45
    • studygolang.com 6 years ago
    • Cache

    Go 语言的 Modules 系统介绍

    即将发布的 Go 语言 1.11 版本将会给我们带来对 modules (模块)的实验性支持,这是 Go 语言新的一套依赖管理系统。 (译注:很多编程语言中,把 modules 译作「模块」,但由于目前该机制在 Go 语言还没正式发布...

  • 73
    • 微信 mp.weixin.qq.com 6 years ago
    • Cache

    为Go语言开发者介绍NATS

  • 33
    • www.tuicool.com 5 years ago
    • Cache

    Golang 语言 - Json基本介绍

    Json概述? JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式,是一种主流的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和...

  • 17

    语言即虚拟机,将 cora 编译到 Go2019-08-04整个周末这两天都在密集地写代码,为 cora 语言实现编译,以至于家里人认为我有点走火入魔了。是啊,掐指一算,又一个七夕都快要到了,为毛我今年还在...

  • 13

    打开 Linux 内核源代码,会发现内核在定义C语言函数时,有很多都带有 “inline”关键字,请看下图,那么这个关键字有什么作用呢?

  • 16

    还记得刚开始接触 C 语言的时候,为了描述一个平行四边形的边长和对角线长,我定义了四个变量:短边长 a,长边长 b,对角线1长 d1,对角线2长 d2。在写代码的过程中,发现又要定义一个平行四边形,于是我不得不又定义了四个变量:a2,b2,d12,d22,结果变量又...

  • 6

    c语言入门8,它是if/else语句的亲戚,switch语句介绍 发表于 2018-11-08 08:...

  • 4
    • www.zenlife.tk 4 years ago
    • Cache

    cora 语言中 let loop 宏的写法

    cora 语言中 let loop 宏的写法2021-01-07在 scheme 语言里面,有个 let loop 宏:(let Label ((Var Init) ...) Body) 比如说从 1 加到 100(let loop ((n 1) (sum 0)) (if (= n 100) su...

  • 8

    经期护理和健康公司 Cora 更新LOGO和包装  评论 收藏...

  • 4
    • www.zenlife.tk 1 year ago
    • Cache

    cora 又双叕重写了

    cora 又双叕重写了2023-08-19按照之前的计划,原本应该是用生成到 C 的方式实现,用 top of stack caching 优化编译。中途做到一半,通过这篇

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK