一个极简(山寨)的 lisp 模块方案

2022-12-01

想到一个极简的 lisp 模块实现方案,记录一下。

先说 elisp,elisp 里面是没有 namespace 等等复杂的概念的,不同 package 之间,为了避免命名冲突,就加上很长的前缀。 其实我觉得前缀长一点也没啥的,只是写起来麻烦一点,至少 elisp 也是可以按 package 去组织代码的。

希望写法可以按这样子写,一个文件就是一个模块。文件的路径就是模块的 import path。

被调用的包 cat /path/to/file1

(defun .f ()
	...)

代码实际变成了

(defun /path/to/file1.f ()
	...)

调用者调用 cat /path/to/another/file2

(import "/path/to/file1" as p)

(defun .g()
	(p.f))

代码实际变成了

(defun /path/to/file2.g ()
	(/path/to/file1.f))

所有的文件内的定义的 symbol,都自动加上了文件的路径,哪怕 symbol 是全局的,由于文件路径的区分,也不会产生模块间的命名冲突。

可以在 reader 那层做点手脚,特殊解析 p.f 这样以点分隔的符号,如果文件头有 import /path/to/file1 as p 就自动将 p.f 转成 /path/to/file1.f。简单的讲,就是存在 import 之后,p.f 就相当于 /path/to/file1.f 的缩写。

实现方式只需要 reader 那边,识别出文件头里面的 import,对后续的词法解析去做替换。

注意到 defun 用到的函数名是 .f.g 这种,而不是 fg,这是做一个扩展,xxx.yyy 如果 xxx 是空的,就是直接指模块自己,展开时追加的是自身的文件路径前缀。

也就是如果想暴露不带前缀的(global)的,那么还是写成

defun f ...

而如果是模块内部的,则是写成

defun .f ...

优点就是这套实现非常简洁,只改改 reader 就完事了。import 变成模块加载都可以直接改写成 load 操作,当然要注意下模块文件只被 load 一次。

coramodule

HNS.to is a highly insecure way of browsing Handshake domains and should only be used for demo or educational purposes. Click to see preferable resolutions methods