产生的文字将会是部分可信的(locally plausible),因为任两个出现的单词也是输入文件里,两个同时出现的单词。令人惊讶的是,获得看起来是 ── 有意义的整句 ── 甚至整个段落是的频率相当高。

    图 8.2 包含了程序的上半部,用来读取示例文件的代码。

    图 8.2 读取示例文件

    从图 8.2 所导出的数据,会被存在哈希表 *words* 里。这个哈希表的键是代表单词的符号,而值会像是下列的关联列表(assoc-lists):

    使用作为示例文件时,这是与键 |discover| 有关的值。它指出了 “discover” 这个单词,在诗里面用了四次,与 “wide” 用了两次,而 “sin” 与 ”sights” 各一次。(译注: 诗可以在这里找到 http://www.paradiselost.org/ )

    函数 read-text 累积了这个信息。这个函数接受一个路径名(pathname),然后替每一个出现在文件中的单词,生成一个上面所展示的关联列表。它的工作方式是,逐字读取文件的每个字符,将累积的单词存在字符串 buffermaxword 设成 ,程序可以读取至多 100 个单词,对英语来说足够了。

    只要下个字符是一个字(由 alpha-char-p 决定)或是一撇 (apostrophe) ,就持续累积字符。任何使单词停止累积的字符会送给 see 。数种标点符号(punctuation)也被视为是单词;函数 punc 返回标点字符的伪单词(pseudo-word)。

    函数 see 注册每一个我们看过的单词。它需要知道前一个单词,以及我们刚确认过的单词 ── 这也是为什么要有变量 prev 存在。起初这个变量设为伪单词里的句点;在 see 函数被调用后, prev 变量包含了我们最后见过的单词。

    现在来到了有趣的部份。图 8.3 包含了从图 8.2 所累积的数据来产生文字的代码。 generate-text 函数导出整个过程。它接受一个要产生几个单词的数字,以及选择性传入前一个单词。使用缺省值,会让产生出来的文件从句子的开头开始。

    图 8.3 产生文字

    要取得一个新的单词, generate-text 使用前一个单词,接着调用 random-nextrandom-next 函数根据每个单词出现的机率加上权重,随机选择伴随输入文本中 prev 之后的单词。

    现在会是测试运行下程序的好时机。但其实你早看过一个它所产生的示例: 就是本书开头的那首诗,是使用弥尔顿的失乐园作为输入文件所产生的。

    (译注: 诗可在这里看,或是浏览书的第 vi 页)

    Half lost on my firmness gains more glad heart,

    Or violent and from forage drives

    A glimmering of all sun new begun

    Forth my early, is not without delay;

    For their soft with whirlwind; and balm.

    Undoubtedly he scornful turn’d round ninefold,

    Though doubled now what redounds,

    And chains these a lower world devote, yet inflicted?

    Till body or rare, and best things else enjoy’d in heav’n

    To stand divided light at ev’n and poise their eyes,

    Or nourish, lik’ning spiritual, I have thou appear.