2015-05-24

变色龙代码

最近的新玩具: https://github.com/coolwanglu/quine-chameleon

受mame的100个语言的quine-relay的启发,我想可否做一个完全图,即多个语言互相转换。
这样的程序英文叫multiquines,Wikipedia上有介绍,程序运行时需要指定一个参数,比如输出语言,然后程序会输出自身代码的对应那种语言的版本。如果指定参数就是这个程序源代码所使用的语言,那就是quine了。

网上有一个5种语言的multiquines,我看了看,不是太优美。我一开始就是朝着multiquines的方向写。然而后来注意到,不指定任何参数的时候对multiquines来说是没定义的(或者什么都不应该输出),这个有点浪费,于是我做了ouroboros(就像quine-relay那样)和随机转换两种模式。

再后来我注意到反而是不指定参数这部分更有趣,而且为了同时支持带参数和不带参数,需要各种判断,造成代码臃肿。于是我就把这两部分拆开,目前在源码中分别叫chameleon.*和multiquines.*。分别进行优化。

写这个东西最大的乐趣当然是不断加入新的语言。我开始不久就把自己熟悉的语言放进去了,然后慢慢添加新语言,不会的就现学现卖。基本上需要的语言特性和函数有如下几个

- 支持双引号定义的字符串,支持反斜杠转义
- 将字符串按分隔符切成数组
- 生成随机数
- 支持命令行参数
- 数组查找
- 字符串转义,或者json输出,或者字符串/正则式替换
- 输出(不带换行)

按目前的设计,第一条决定了一个语言是否能很容易的加入。这里比quine-relay难的地方在于,任何两个语言都要互相输出,所以最好能有一个公共的转义和还原的标准。而quine-relay中每个语言只需要考虑下一个语言的转义就好了,更方便预处理,支持新语言(比如whitespace,brainfuck)以及其他特性(比如字符串压缩)

我在写这个玩具的过程中也很自然的学习了一些新语言。之前为了写dunnet.js而研究了emacs lisp,这里还加入了其他lisp系列比如clojure,racket,发现写写脚本也还挺顺手的。只可惜scheme由于标准库太小以及srfi实现不统一没能加入。另外就是接触了之前完全不想接触的perl和awk,发现不但没有想像中的可怕,反而挺好用的。

ruby出乎我的意料,一直是各个语言中最短的,尤其multiquines的原始代码(不包含数据)只有80个字节!然而一般python就够我用了,也没有太大动力学新的。coffeescirpt和javascript经过不断优化也冲到了前面,不错!

其他值得一提的是,即使是之前比较陌生的go,lua,vala,我都能很快上手,一方面说明了文档齐全,互联网时代获取知识非常容易,另一方面我也觉得现代编程语言比较类似,语言本身已经成为了工具,脑子里有一些大概念就可以畅行无阻了。当然具体细节还是要慢慢学习和熟悉。

至于C家族,你们就乖乖在最后好好歇着吧。。。