后来,当我们学会了如何去,欸?

事情开始是怎么样的我忘了。朦胧中印象是很多年前,一个月黑风高的下午,某写了Clojure iPython Notebook的The Clojurer You Know Who见到了Pony的两位作者然后说写个Pony的iPyothon Notebook对于我来说简直分分钟的事情啊。于是相谈甚欢这就要开始整了。然后我说你给Prolog也写一个啊当然回答是:你丫不会自己写啊!

那我说看看吧,这就麻烦了。你要开始写吧,第一步就是你的语言要有个ZeroMQ的客户端吧,不能直接鸡同鸭讲啊!你要写客户端,首先要看鸡同鸭讲什么吧。于是就发现ZeroMQ要跟iPython的服务讲json啊。可是,我们Prolog,呃,真的没有json的库啊!

作为一个发过誓这辈子就是都看得懂也不去学写Javascript的人,其实我当场挺高兴的。你说:什么?这年头还有不支持json的语言?呃,在我们Prolog界,支持http的都只有SWI Prolog一家,你们json算个什么东西!

于是我去瞄了一眼RFC7159,呃,像parse个这样自己的BNF定义也没有几个字的东西,对于Prolog,完全几乎就是不用写啊。然后真的就,当场就写完了。由于太快,写完也就给忘了。。。

然而你们没有看两句看到这样的写法:

nm_token([H|T]) -->  
    [H],
    { minus(H);digit_table(H) },
    nm_token1(T).

稍有常识的人都会知道,这看上去不完全是Prolog啊,这些-->和花括号是什么东西!我们先不管这时候嘿嘿一笑的老司机们。即使不知道这是什么的,玩过Antler的同学这会儿也会有似曾相识的感觉,有木有!有木有!

这就是Prolog传说中的Definite Clause Grammars啊。Antler跟这长得那么像,因为也是一模一样的思路啊。本质上就是Prolog实现的context-free grammar,所以说你拿着一个BNF的语法来,几乎直接就可以翻译成它不费吹灰之力的来写parser了。而Prolog在解释和编译的时候,又可以非常容易得把DCG转换成普通的Prolog predicates。效果最好的话,就是你拿着这一百来行和json的BNF spec对比看,有没有发现我几乎是逐句翻译的。(是的,甚至有翻译工具的)

这期几乎屁也没有讲就算完了么?并没有,我这里还要留个噱头。(烧死

其实像

head --> body  

这样的DCG语法,包括它是如何翻译到平常的Prolog predictes的,也并不是解释器和编译器搞的鬼。而是,呃,完全依靠Prolog魔改定义的。你可以定义一套自己的像DCG一样的语法/词法,然后用它们,最后在编译/解释期把自己的鬼DSL变成Prolog。这就是传说中的Prolog term_expansion大法了。。。有些lisp系的小盆友这时候已经在东边墙角开始吼Macro!Macro!Macro!了。。。但其实也不完全是了,Prolog这一套魔改的玩法还是很强大的,你们整一整就会发现了。于是我决定下期讲了(逃