文化编程

莫看,莫看,莫看。重要的事说三遍,浪费时间我无论。

文化编程(Literate Programming)由计算机学界名宿 Donald Knuth 所创。其名,大陆译为「文学编程」,甚缪。将程序视为蛮夷,以文教化,Literate Programming 之意大抵如是。git

文化,其目的在于实现人与人的沟通交流。假若这世上只有一人,文化是多余的。同理,假若世上只有一个编程者,文化编程也是多余的。程序的属性分为两部分,一是供机器执行,二是供人类阅读。程序能正确被机器执行,这是第一性,但程序要继续维护下去,其代码更易于为他人理解,这是第二性,两者缺一不可。因此,程序要有文化。github

Knuth 创立文化编程,江湖传言,是报 E. W. Dijkstra 的一箭之仇。 Dijkstra 也是计算机学界名宿。当年,他提出告终构化编程,指出应当像设计机器那样编写程序,而 Knuth 写的程序不够结构化,或许为此而不快。创立文化编程以后,Knuth 就能够说 Dijkstra 没文化,固然他不会这样说。编程

江湖恩仇,儿女情长,这些事,提及来没完没了,到此为止。这篇文章,真正的主角是我。segmentfault

Knuth 虽然提出了文化编程,惋惜的是,他创造的文化编程工具 CWEB 有历史局限性,如今不是很好用。这能够理解,毕竟这个工具最初是他自用,而且在写这个工具之时,也只有美国人有更多的机会使用计算机。工具

好在这种工具实现起来也不太难,去年过年的那段时间,我写了一个相似的工具,名曰 orez,意思是 zero 翻转。为了防止百年以后有人再乱翻译,我先将它翻译为逆零 :)ui

有文化的代码

orez 基本上遵循 CWEB 的思路——程序的代码与文档,彼此独立,但又混而为一。若以泡茶为喻,则代码之于茶叶,文档之于水,而 orez 之于茶壶。代码与文档的混合体,可称之为有文化的代码。翻译

代码与文档的混合须要借助一组简单的标记方能实现。下面,以一组五言诗句(姑且当其是)为代码,以诗句解析做为文档,演示这些标记的用法。这组诗句很直白,是一位无名氏,于一次磨刀以后随手而做,记录了磨刀的过程,赞美了磨过以后刀如何锋利,最后感慨真正锋利的刀无人赏识而隐没于陋鞘。设计

代码与文档皆以段落的形式出现,而且老是以 @ 符号领起。例如:code

@ 一位侠士用水浸泡砥石,准备亲手去磨已钝了的未名刀:

@ 准备 #
沧浪三瓢水
砥石浴盆中
侠士自磨刀
霜刃名未名

两者的区别是,代码段落有名字,即 @# 之间的文字,例如「准备」。代码段落的名字可根据实际状况而取,此处仅仅是追求足够简单。文档

假若有文化的代码是以文档开始,那么首个文档段落的领起符号可省略。例如:

侠士用水浸泡砥石,准备亲手去磨已钝了的未名刀:

@ 准备 #
沧浪三瓢水
砥石浴盆中
侠士自磨刀
霜刃名未名

若假设代码段落以后总存在一个文档段落,哪怕这个段落没有任何内容,那么文档段落的领起符即可以在形式上做为代码段落的终止符。虽然没必要非如此不可,可是在以文档段落开始的状况下,我更喜欢这种形式。例如:

侠士用水浸泡砥石,准备亲手去磨已钝了的未名刀:

@ 准备 #
沧浪三瓢水
砥石浴盆中
侠士自磨刀
霜刃名未名
@

这样一来,若代码段落后面是文档段落,那么该文档段落领起符已存在。若代码段落后面依然是代码段落,那么两者之间会夹杂一个内容为空的文档段落,无碍。

接下来再继续增长文档段落与代码段落:

磨刀,主要是靠腰部力量,手起到固定刀片倾斜角度的做用:

@ 姿式 #
力从足下起
腰旋若扭松
双手互犄角
刃行掠风轻
@

刀片在砥石上的前进方向老是与锋线垂直,而且须要时不时用手试
一下刀锋是否已磨到卷边的程度:

@ 技巧 #
锋线有曲直
法向自无知
进退两茫然
探手试微疵
@

假设全部的文档段落与代码段落皆已写出,那么最后可经过代码段落的引用标记,将全部已给出的代码段落汇总到一块儿。例如:

@ 磨刀歌 #
# 准备 @

# 姿式 @

# 技巧 @

... ...
@

形如 # ... @ 这样的结构,即是已给出的代码段落的引用,亦即所引用的代码段落的内容最终会嵌入到被引用处。同一个代码段落,可于多处被引用。

貌离神合

假若不想为每一个代码段落都取个名字,毕竟取名字很烦人,能够考虑使用同名代码段,运算符 + 用于标记同名代码段落内容链接起来,表示一个完整的代码段落。

例如:

侠士用水浸泡砥石,准备亲手去磨已钝了的未名刀:

@ 磨刀歌 #
沧浪三瓢水
砥石浴盆中
侠士自磨刀
霜刃名未名
@

磨刀,主要是靠腰部力量,手起到固定刀片倾斜角度的做用:

@ 磨刀歌 # +
力从足下起
腰旋若扭松
双手互犄角
刃行掠风轻
@

刀片在砥石上的前进方向老是与锋线垂直,而且须要时不时用手试
一下刀锋是否已磨到卷边的程度:

@ 磨刀歌 # +
锋线有曲直
法向自无知
进退两茫然
探手试微疵
@

上述三个代码段落,虽然分散各处,但它们其实是由两个 + 运算符链接而成的一个总体:

@ 磨刀歌 #
沧浪三瓢水
砥石浴盆中
侠士自磨刀
霜刃名未名
力从足下起
腰旋若扭松
双手互犄角
刃行掠风轻
锋线有曲直
法向自无知
进退两茫然
探手试微疵
@

+ 运算符表示自上而下顺次链接同名的代码段落,其逆运算符 ^+ 则表示自下而上链接同名的代码段落。例如:

@ 磨刀歌 # ^+
磨刀歌

无名氏

@

这时,完整的代码段落以下:

@ 磨刀歌 #
磨刀歌

无名氏

沧浪三瓢水
砥石浴盆中
侠士自磨刀
霜刃名未名
力从足下起
腰旋若扭松
双手互犄角
刃行掠风轻
锋线有曲直
法向自无知
进退两茫然
探手试微疵
@

标签

有时,须要将一个代码段落链接到某个特定的同名代码段落以前或以后,这时须要借助标签。

首先须要在目标段落上放一个标签。例如:

@ 磨刀歌 #
<第一节>
沧浪三瓢水
砥石浴盆中
侠士自磨刀
霜刃名未名
@

<第一节> 即标签。标签必须置于代码段落标题行的下一行,且独占一行。

在源段落中,将目标段落标签与 +^+ 运算符组合起来,即可将源段落与目标段落链接起来。例如:

@ 磨刀歌 # <第一节> ^+
磨刀歌

无名氏

@

结果依然是:

@ 磨刀歌 #
磨刀歌

无名氏

沧浪三瓢水
砥石浴盆中
... ...
@

输出

假设程序代码与文档内容混合体——有文化的代码,存于文本文件 foo.orz。如今,若从中导出给人看的文档——可喻为倒茶喝,只需使用如下命令:

$ orez -w foo.orz -o foo.yml

生成的 foo.yml 是一份带有排版信息的中间文件,它最终能转化为何文件,这取决于程序代码与文档内容是基于何种排版语言混而为一。假若是基于 Markdown 语言,即可使用 orez-md 工具,将 foo.yml 转换为 foo.md 文件(Markdown 文件),而后,再用其余工具将 foo.md 文件转化为网页或其余形式的文档形式。

在 Linux 系统(或类 Unix 系统)中,从 foo.orz 到 foo.md 的整个过程,可浓缩为一条命令:

$ orez -w foo.orz | orez-md > foo.md

foo.md 就是从 orez 这个茶壶嘴里流出的茶水。

一壶茶喝到了没滋味的时候,又该怎样倒出茶叶呢?打开壶盖,倒出来。不过,为了更贴近 orez 的逻辑,须要将茶叶视为袋泡茶,揪住袋上棉线,将茶叶从茶壶中拎出来。例如:

$ orez -t -e "磨刀歌" foo.orz -o mdg.txt

最后所得 mdg.txt 文件即是以 磨刀歌 为棉线而拎出的袋泡茶。

尾巴

更多细节见 《orez 的故事》。之因此又重写一篇简略介绍,是由于之后要用 orez 的一些标记。

相关文章
相关标签/搜索