用lisp来让计算机学会写作
大部分的代码、思路参考了《Ansi Common Lisp》P138~P141。
问题:给一篇英文文本,如何让计算机依据此文本而生成随机但可读的文本。如:
|Venture|
The National Venture Capital Association estimates that wealth associated with a deal a big spending by regulations that will spend one another's main reason these projects .
这是计算机学习了Paul Graham的一些文章后生成的随机文本。它根据Venture这个单词向两边延伸成一个句子。令人惊喜的是,文本常常是可读的。
算法:记录每个单词后面出现的单词以及出现的次数,如I leave在原文中出现了5次,I want出现了3次,除此之外,其它地方没有出现过I,所以在生成随机文章的时候,当遇到I,有5/8的概率选择leave为下一个单词。假如选择了leave的话,则看看leave后面出现过哪些单词,重复以上过程。
现用lisp来解决问题。
lisp里的符号类型,即symbol,可以很好记录各种字符串还有标点符号,所以采用它来记录。采用内附的hashtable来建立列表:
(defparameter *words* (make-hash-table :size 10000))
那如何建立列表呢?
(let ((prev '|.|))
(defun see (sym)
(let ((pair (assoc sym (gethash prev *words*))))
(if pair
(incf (cdr pair))
(push (cons sym 1) (gethash prev *words*))))
(setf prev sym)))
以当前单词为keyword,以assoc-list关系列表为该keyword下的值。
如I下有( (|leave| . 5) (|want| . 3) )。没有单词word的话,则push入(word . 1)。
如何随机选一个词呢?
(defun random-word (word ht)
(let* ((choices (gethash word ht))
(x (random (reduce #'+ choices :key #'cdr))))
(dolist (pair choices)
(decf x (cdr pair))
(if (minusp x)
(return (car pair))))))
这里巧妙用了reduce函数。
现在再来思考,如何将给定一个词向两侧延伸成一句话呢?
1)先将文本反向,得到一个反向的列表,也即I leave,I want变成leave I,want I。
2)将hashtable反向,得到另外一个hashtable,以后一个单词为关键字,前面可能出现的单词及次数构成assoc-list。
3)碰运气,从一个标点开始延续文章,直到出现给定单词为止。
我用了第二个方法:
(defparameter *r-words* (make-hash-table :size 10000)) (defun push-words (w1 w2 n)
(push (cons w2 n) (gethash w1 *r-words*))) (defun get-reversed-words ();a cat -> cat a
(maphash #'(lambda (k lst)
(dolist (pair lst)
(push-words (car pair) k (cdr pair))))
*words*))
遍历原来的hashtable,再把每一对单词先后换个位置插入另外一个hashtable。
给出双向延伸句子的自动生成文本代码:
(defparameter *words* (make-hash-table :size 10000))
(defconstant maxword 100)
(defparameter nwords 0)
(defconstant debug nil)
(let ((prev '|.|))
(defun see (sym)
(incf nwords)
(let ((pair (assoc sym (gethash prev *words*))))
(if pair
(incf (cdr pair))
(push (cons sym 1) (gethash prev *words*))))
(setf prev sym))) (defun check-punc (c);char to symbol
(case c
(#\. '|.|) (#\, '|,|)
(#\; '|;|) (#\? '|?|)
(#\: '|:|) (#\! '|!|))) (defun read-text (pathname)
(with-open-file (str pathname :direction :input)
(let ((buf (make-string maxword))
(pos 0))
(do ((c (read-char str nil 'eof)
(read-char str nil 'eof)))
((eql c 'eof))
(if (or (alpha-char-p c)
(eql c #\'))
(progn
(setf (char buf pos) c)
(incf pos))
(progn
(unless (zerop pos)
(see (intern (subseq buf 0 pos)))
(setf pos 0))
(let ((punc (check-punc c)))
(if punc
(see punc))))))))) (defun print-ht (ht)
(maphash #'(lambda (k v)
(format t "~A ~A~%" k v))
ht)) (defparameter *r-words* (make-hash-table :size 10000)) (defun push-words (w1 w2 n)
(push (cons w2 n) (gethash w1 *r-words*))) (defun get-reversed-words ();a cat -> cat a
(maphash #'(lambda (k lst)
(dolist (pair lst)
(push-words (car pair) k (cdr pair))))
*words*)) (defun print-a-word (word ht)
(maphash #'(lambda (k lst)
(if (eql k word)
(format t "~A ~A~%" k lst)))
ht)) (if debug
(print-a-word '|leave| *r-words*)) (defun punc-p (sym);symbol to char,nil when fails.
(check-punc (char (symbol-name sym) 0))) (defun random-word (word ht)
(let* ((choices (gethash word ht))
(x (random (reduce #'+ choices :key #'cdr))))
(dolist (pair choices)
(decf x (cdr pair))
(if (minusp x)
(return (car pair)))))) (defun gen-former (word str)
(let ((last (random-word word *r-words*)))
(if (not (punc-p last))
(progn
(gen-former last str)
(format str "~A " last))))) (defun gen-latter (word str)
(let ((next (random-word word *words*)))
(format str "~A " next)
(if (not (punc-p next))
(gen-latter next str)))) ;(gen-latter '|leave| t) (defun get-a-word (ht);get a random word
(let ((x (random nwords)))
(maphash #'(lambda (k v)
(dolist (pair v)
(decf x (cdr pair))
(if (minusp x)
(return-from get-a-word (car pair)))))
ht)))
;(get-a-word *words*)
(defun gen-sentence (word str)
(gen-former word str)
(format str "~A " word)
(gen-latter word str)) (defun test ()
(setf nwords 0)
(read-text "essay.txt")
(get-reversed-words)
(let ((word (get-a-word *words*)))
(print word)
(gen-sentence word t)))
(test)
文本语料库、lisp源代码见:
Here
用lisp来让计算机学会写作的更多相关文章
- 芮勇博士荣获2016年IEEE 计算机学会技术成就奖
微软亚洲研究院常务副院长 芮勇 日前,电气电子工程师学会(the Institute of Electrical and Electronics Engineers, IEEE)计算机学会(Comp ...
- 计算机顶级会议Rankings && 英文投稿的一点经验
英文投稿的一点经验[转载] From: http://chl033.woku.com/article/2893317.html 1. 首先一定要注意杂志的发表范围, 超出范围的千万别投,要不就是浪费时 ...
- 震惊!CCF改名为中国沙雕化学学会!!!
震惊!中国沙雕计算机学会要改名中国沙雕化学学会??? Ak元素 据传,CCF,发现了一种新元素,元素符号暂命名为为Ak,中文名称暂未命名,据说是第250号元素. Ak 元素的发现 珂学家在一个叫洛谷的 ...
- 为什么Lisp没有流行起来
很久以前,这种语言站在计算机科学研究的前沿,特别是人工智能的研究方面.现在,它很少被用到,这一切并不是因为古老,类似古老的语言却被广泛应用.其他类似的古老的语言有??FORTRAN. COBOL. L ...
- 你的计算机也可以看懂世界——十分钟跑起卷积神经网络(Windows+CPU)
众所周知,如果你想研究Deep Learning,那么比较常用的配置是Linux+GPU,不过现在很多非计算机专业的同学有时也会想采用Deep Learning方法来完成一些工作,那么Linux+GP ...
- PayPal高级工程总监:读完这100篇论文 就能成大数据高手(附论文下载)
100 open source Big Data architecture papers for data professionals. 读完这100篇论文 就能成大数据高手 作者 白宁超 2016年 ...
- PayPal 高级工程总监:读完这 100 篇文献,就能成大数据高手
原文地址 开源(Open Source)对大数据影响,有二:一方面,在大数据技术变革之路上,开源在众人之力和众人之智推动下,摧枯拉朽,吐故纳新,扮演着非常重要的推动作用:另一方面,开源也给大数据技术构 ...
- SCI&EI 英文PAPER投稿经验【转】
英文投稿的一点经验[转载] From: http://chl033.woku.com/article/2893317.html 1. 首先一定要注意杂志的发表范围, 超出范围的千万别投,要不就是浪费时 ...
- 《计算机程序的构造和解释(第2版)》【PDF】下载
<计算机程序的构造和解释(第2版)>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230382255 内容简介 <计算机程序的构造 ...
随机推荐
- Multiple markers at this line @Override的解决方法
Multiple markers at this line - implements java.awt.event.ActionListener.actionPerformed - The metho ...
- 基于visual Studio2013解决C语言竞赛题之0402奇偶求和
题目 解决代码及点评 这道题考察我们对循环和判断的综合应用 #include <stdio.h> #include <stdlib.h> #include < ...
- 剖析MFC六大关键技术(五六)--消息映射与命令传递
说到消息,在MFC中,“最熟悉的神秘”可算是消息映射,那是我们刚开始接触MFC时就要面对的东西.有过SDK编程经验的朋友转到MFC编程的时候,一下子觉得什么都变了样.特别是窗口消息及对消息的处理跟以前 ...
- UITableView 协议中常用的方法
UITableViewDataSource 协议中常用方法 1.设置右边 索引值 - ( NSArray *)sectionIndexTitlesForTableView:( UITableView ...
- C# 调用迅雷 7 迅雷下载开放引擎
最近有个项目需要用winform调用迅雷下载.上网百度后发现迅雷自带的com组件从迅雷5之后就废掉了,除了能添加任务,其余功能全不能用.后来又发现了迅雷下载开放引擎这么个东西 http://thund ...
- sqlite3 脚本的使用
本来想找个专门查看数据库的工具的,后来发现脚本也非常easy,就直接用脚本了. sqlite3的脚本能够方便的查看当前数据库里的内容,使用起来事实上非常easy,这一列举一些最简单的使用方法,以后假设 ...
- eclipse config 3 构造pydev
什么是不是说生命是短暂的.我用python 准备工作 sudo apt-get install python3-dev 例如以下操作 依次点击菜单 Help->Install New Softw ...
- linux中/etc与/var目录,各是什么意思?这两个目录下的文件有什么特点?
http://zhidao.baidu.com/link?url=DkxU9CyhJb_dIUAPCmPmxRtQsENgCzqy5qnLPEj_V9DqNzdt6Qya0U5iCVRCYFkgoRo ...
- javascript 学习随笔
var carname="Volvo"; var carname; 重新声明变量后变量的值不变,在这里还是volvo var carname="Volvo"; ...
- Reapter 添加删除按钮
repeater中的删除按钮和datagrid下的删除在实现上,还是有一定的区别的,由于repeater在客户端生成的html代码是非常干净的,所以特别受到众多web2.0网站的欢迎(不像datagr ...