21天学通Erlang

2015年10月18日

如何同步代码片段

因为21天学通Erlang是面向零基础的初学者的,长一点的代码肯定不会是一次写成的,是要分成很多步的。为了方便读者参考,同时也是为了能检验这中间每一步是不是真的没问题,所以每一步都会有一个单独文件,这个文件也要以和最终结果一样的方式检查。假如一个代码片段同时出现在很多个文件里,为了改这个片段,得同时编辑这些文件。这样真是非常非常麻烦,更大的麻烦是没办法检查同一个代码片段在多个文件里是否一致。

于是,我们用snip.py来应付这些问题。给代码片段起个名字,比如下面这个例子中叫my-first-snippet,把代码片段写在% SNIP BEGIN% SNIP END之间,这样就可以根据名字来判断是不是同一个片段了。

% SNIP BEGIN my-first-snippet
hello() ->
    world.
% SNIP END

运行snip.py build之后,这些注释都会被删掉,就变成下面这样。

hello() ->
    world.

Erlang中还有一种特殊的情况,clause之间是用;分开的,但是最后一个clause结尾处用的是.。此时可以用%- SNIP END。这样build后,会把注释前后两行接成一行,不会出现;.分别单独占一行的情况。比如下面这个例子中,在第一个文件里,只有一个clause。

% SNIP BEGIN my-second-snippet
hello(1) ->
    world
%- SNIP END
.

运行snip.py build之后,就变成下面这样。

hello(1) ->
    world.

在第二个文件里,有两个clause。

% SNIP BEGIN my-second-snippet
hello(1) ->
    world
%- SNIP END
;
hello(2) ->
    big_world.

运行snip.py build之后,就变成下面这样。

hello(1) ->
    world;
hello(2) ->
    big_world.

因为恰好LaTeX和Erlang注释用的都是%。可以在LaTeX文档里也可以用同样的记号。为了能在PDF里看到代码片段所在的文件名和行号,需要使用% SNIP REFERENCE

% SNIP REFERENCE hello.erl my-first-snippet
\begin{SourceCode}
% SNIP BEGIN my-first-snippet
hello(1) ->
    world.
% SNIP END
\end{SourceCode}

修改过代码后,运行snip.py status会列出所有不同步的代码片段的名字,接着就可以用snip.py sync来选择某个文件里的片段,把所有文件里的同名代码片段都修改成一样的。

2015年10月11日

核对Erlang Shell会话的记录

和其他脚本语言的入门教程一样,21天学通Erlang里也会有很多Shell会话的记录。每次生成PDF时,都去人工检查一遍,不仅费时费力,还很容易出错。

为了方便检查这些记录,定义ErlangShellSession这个environment,把LaTeX文档中所有Erlang Shell会话记录输出到单独的文件,这样接下来就只要分别检查这些文件就可以了。

\newcounter{erlangshellsession}[section]
\newoutputstream{erlangshellsession}
\newenvironment{ErlangShellSession}{
\stepcounter{erlangshellsession}
\openoutputfile{\currfiledir\theerlangshellsession.session}{erlangshellsession}
\writeverbatim{erlangshellsession}
}{
\endwriteverbatim
\closeoutputstream{erlangshellsession}
\begin{SingleSpacing}
\lstinputlisting[title={Erlang Shell}]{\currfiledir\theerlangshellsession.session}
\end{SingleSpacing}}

很糟糕的是,OTP并没有包含类似Python里的doctest的功能。Erlang作者之一,Joe Armstrong不久前也在Erlang Questions邮件列表上问如何实现类似的功能[1]

Erlang Shell和一般的REPL在功能上有些出入,而且文档也不全。启动Shell的process,得先把自己设置成group leader,这样才能以I/O protocol与Shell通信。收到get_until消息,那么就向Shell发送他想要的内容。收到put_chars消息,就把这些字符和记录去比较。假如所有记录内容都已经比较完了,也没有出现不同,那么就向Shell发送eof消息,等Shell退出。

[1]Programmatic interface to the shell
2015年10月04日

为什么21天能学通Erlang

21天学通一门程序语言,很多人都认为不现实。比如,Peter Norvig就认为需要十年。还有广为流传的漫画指出,唯一的办法从遥远的未来回到第21天干掉那时的自己。

只是学写个程序,用不着这么残忍。他们都犯了地球中心主义的错误。21天不必是地球上的21天。宇宙这么大,你肯定能找到一个星球。在那个星球上,以你开始学Erlang的那天作为第1天,等你学通Erlang的那天是第21天。这和Perl 6一定会在圣诞节发布[1]是同一个道理。

这就是为什么书名并没有骗你。

[1]

When Perl 6 arrives, every day will be like Christmas!

Pugs, an implementation of Perl 6

1 / 1