熟练使用文学编程(literate programming)是怎样一番体验?

你有它来写过哪些小中大程序? 你在你的OS上是如何配置这套工具链的呢? 欢迎对问题进行补充。
关注者
535
被浏览
20627

7 个回答

@bhuztez 邀请,你终于换了头像了。

说到文学编程,我算是有点发言权的。弄过WEB和CWEB,中间还玩过Haskell。都有文学编程。
我不建议使用文学编程,因为常人容易掉到坑里面,比如,我们来看看TeX里面的代码吧:
@p @!init function get_strings_started:boolean; {initializes the string pool,
  but returns |false| if something goes wrong}
label done,exit;
var k,@!l:0..255; {small indices or counters}
@!m,@!n:text_char; {characters input from |pool_file|}
@!g:str_number; {garbage}
@!a:integer; {accumulator for check sum}
@!c:boolean; {check sum has been checked}
begin pool_ptr:=0; str_ptr:=0; str_start[0]:=0;
@<Make the first 256 strings@>;
@<Read the other strings from the \.{TEX.POOL} file and return |true|,
  or give an error message and return |false|@>;
exit:end;
tini
这个是一段Pascal代码,其中@<Make the first 256 strings@>这个部分是一小块代码,长这样:
@<Make the first 256...@>=
for k:=0 to 255 do
  begin if (@<Character |k| cannot be printed@>) then
    begin append_char("^"); append_char("^");
    if k<@'100 then append_char(k+@'100)
    else if k<@'200 then append_char(k-@'100)
    else begin app_lc_hex(k div 16); app_lc_hex(k mod 16);
      end;
    end
  else append_char(k);
  g:=make_string;
  end
文学编程就是把代码撕裂成多个代码片段,然后在通过拼接构成一个软件。

这听起来就像在拿着剪刀浆糊在弄程序。虽然我个人还真有点喜欢这一套,但是,这种东西实际上会造成两方面的问题:代码不好维护;代码容易写的很ad hoc。前者有一个例子,就是pdfTeX,要知道pdfTeX的早期版本是支持对PDF进行加密的,但是后来移除了,主要原因就是很不好维护,加密代码散见于数十段代码中,只要PDF标准一更新,这些代码全完。后者的例子,其实算是这种编程方法带来的必然结果,TeX本身的代码就有些ad hoc,因为这种写软件的方法是自底而上的办法,中间歪一点最终就成比萨斜塔了。

通常而言,文学编程不适合分拆成多个文件,当然真有这么干的,比如LuaTeX,这就造成代码阅读上更加困难,我当年之所以放弃LuaTeX的扩展就有一点是这个原因。LuaTeX的开发者的CWEB真的真的用的很烂。写成一个文件的例子太多,Knuth的一些列工具基本上都是一个文件。

文学编程还有一个坑,就是打补丁,用tie或者ctie打补丁,补丁的形式基本上是这样:
@x [8.110] l.2422 - increase |max_halfword|
@d min_halfword==0 {smallest allowable value in a |halfword|}
@d max_halfword==65535 {largest allowable value in a |halfword|}
@y 2424
@d min_halfword==-@"FFFFFFF {smallest allowable value in a |halfword|}
@d max_halfword==@"FFFFFFF {largest allowable value in a |halfword|}
@z
这种补丁基本上是手写。有人问,为什么不用diff?那个时候没有diff啊!这个工具就这么一直用下来的。实际上,我是野路子出来的,我个人还真喜欢用tie/ctie,用的最早的东西都是印象最深的。当然,用刀用剑都是武器,比给我安利什么diff,我又不是没用过。

说了写,说了打补丁,接下来该说啥?那就算:把代码拆出来,把文档摘出来。WEB的工具是tangle和weave,这俩词啥意思你们翻翻词典。CWEB就是给这俩工具加个前缀c,即ctangle和cweave。tangle是把代码拆出来的,而weave是生成文档的。前者会将代码拆出来,拆到你自己都不认识,这样要是你源码写错一点,报错你都看不懂,乱七八糟,只能把源码中的代码部分仔细检查一遍,然后进行修正。而后者比较简单,就是生成文档的,生成的文档还是比较好读的,但是仔细阅读还是会发现令人发指的代码。

文学编程就真正是这样了,你们千万别跳到这个坑里。这真是个坑,想想,现代的软件构建方法多好的,何必再用这种不太人道的工具呢?当然,我是个例外,我是TeX开发者,脏活累活都得我干,所以,我们搞TeX开发的还真是很苦逼呢。
这个是《Coders at Work》作者的一篇 essay。
Code is not literature

他访问过很多成名的程序员。他对系统的阅读 code 持否定意见。我对「系统的」阅读的定义是,本身没有任何目的,希望像消费一本小说那样消费一个 code base,期待自动的获得知识。虽然我花过很多时间读 Linux kernel 和 Lua,但是每次读一定要给自己定一些探索小问题的目标。我觉得 literate program 并不是为了工程上的,以扩展原有系统为具体目的的阅读代码准备的,而是希望 code 成为能够被「系统化」(文学化)阅读的东西。这个我持否定态度。
为什么?