图书馆借阅的FOP代码

uda1341

FOP:Fact Oriented Programming

lang rationese

;;;(图书 ?编号 ?书名 ?作者 ?出版社 ?价格)
(图书 0001 治理地方公共经济 ((罗纳德.J.奥克森 著) (万鹏飞 译)) 北京大学出版社 20.00)
(图书 0002 人类的趋社会性及其研究 (赫伯特.金迪斯 萨缪.鲍尔斯) 上海世纪出版集团 24.00)
(图书 0003 空间与社会 刘海岩 天津社会科学院出版社 22.00)
(图书 0004 我仍在苦苦跋涉 牛汉 三联书店 29.00)
(图书 0005 中国制度变迁的案例研究 张曙光 (中国财政经济出版社 浙江大学出版社) 46.00)
(图书 0006 (圣殿春秋 上) ((肯.福莱特 著) (胡允恒 译)) 上海译文出版社 29.00)
(图书 0007 东藏记 宗璞 人民文学出版社 18.00)
(图书 0008 魔山 ((托马斯.曼 著) (钱鸿嘉 译)) 上海译文出版社 45.00)
(图书 0009 十二楼 李渔 人民文学出版社 13.20)
(图书 0010 (圣殿春秋 下) ((肯.福莱特 著) (胡允恒 译)) 上海译文出版社 32.00)
(图书 0011 (圣殿春秋 上) ((肯.福莱特 著) (胡允恒 译)) 上海译文出版社 29.00)
(图书 0012 (圣殿春秋 下) ((肯.福莱特 著) (胡允恒 译)) 上海译文出版社 32.00)
(图书 0013 魔山 ((托马斯.曼 著) (钱鸿嘉 译)) 上海译文出版社 45.00)


;;;(图书状态 ?图书编号 ?状态)
(图书状态 0002 (馆藏 03))
(图书状态 0011 (借阅 05))

;;;(借阅卡 ?编号 ?人名)
(借阅卡 01 张三)
(借阅卡 02 李四)

;;;在当前世界的逻辑查询

;;;根据书名查询,
(rule (根据书名查询 ?书名 ?结果)
(图书 ?编号 ?书名 ?作者 ?出版社 ?价格)
(= ?结果 (图书 ?编号 (?书名 . _) ?作者 ?出版社 ?价格)))
(rule (根据书名查询 ?书名 ?结果)
(图书 ?编号 (?书名 . _) ?作者 ?出版社 ?价格)
(= ?结果 ((图书 ?编号 (?书名 . _) ?作者 ?出版社 ?价格))))

;;;查询示范
>(根据书名查询 圣殿春秋 ?结果)
?结果=((图书 0010 (圣殿春秋 下) ((肯.福莱特 著) (胡允恒 译)) 上海译文出版社 32.00)
(图书 0011 (圣殿春秋 上) ((肯.福莱特 著) (胡允恒 译)) 上海译文出版社 29.00)
(图书 0012 (圣殿春秋 下) ((肯.福莱特 著) (胡允恒 译)) 上海译文出版社 32.00))

;;;时态查询,时态查询通常返回一个世界状态,或者多个世界状态
;;;缺省地,系统中有一个事实(time ?time),在初始状态下,这个值为0,世界每向前进行一步,
;;;这个值就会加1,这为引用过去提供了方便
;;;(time-world ?time ?world) ;查询到某个时刻的world
(time-world ?time ?world)
;;;(now ?time) 得到当前时刻
(now ?time)
;;;(prev ?world) 之前的那个时刻
(rule (prev ?world) (is ?time1 ?time-1))
;;;after 在?q成立之前
(after ?q ?worlds)
;;;before 在?q成立之后
(before ?q ?worlds)
;;;fromto 在?q1成立和?q2成立之间
(fromto ?q1 ?q2 ?worlds)
;;;since 从?q成立到现在
(since ?q ?worlds)
;;;last-time 上一个世界状态
(last-time ?world)
;;;last-time 上一次事实成立时
(last-time ?q ?world)

;;;有用的时态查询:历时的事件
;;;一次借阅,借阅过程开始于(command 借阅),结束于(command 借阅成功)
;;借阅是经历一段时间的事件,这个事件不是瞬间完成的.
;;;下面的规则查询到历史上发生过的借阅
(rule (借阅事件 ?worlds)
(fromto (command 借阅) (command 借阅成功) ?worlds))
;;;每个借阅事件都关联到一个图书编号和一个借阅证编号
(rule (借阅时间 ?图书编号 ?借阅证编号 ?worlds)
(fromto (command 借阅) (command 借阅成功) ?worlds)
(query-in (command 借阅 ?图书编号 ?借阅证编号) ?worlds))
;;;这样就可以查询某本图书的借阅历史
(rule (图书借阅历史 ?图书编号 ?worlds)
(借阅事件 ?图书编号 _ ?worlds))
;;;还可以查询某个借阅证的借阅历史
(rule (借阅证借阅历史 ?借阅证编号 ?worlds)
(借阅事件 _ ?借阅证编号 ?worlds))


(rule (图书可借阅 ?图书编号) (图书状态 ?图书编号 (馆藏 _)))

;;;动作定义
(rule (借阅 ?图书编号 ?借阅卡编号)
(图书可借阅 ?图书编号)
(modify (图书状态 ?图书编号) (图书状态 (借阅 ?借阅卡编号))))

;;;responses

(response (command run)
(output 0 "欢迎使用图书借阅系统"))
(response (command exit)
(output "程序结束"))
(response (command (query ?q))
(query ?q ?result)
(output 0 ?result))
(response (command 借阅)
(output 0 "扫描图书编号:")
(order (command 扫描图书编号)))
;;;扫描图书编号: 从端口1输入?图书编号,转到检查图书编号
(response (command 扫描图书编号)
(input 1 ?图书编号)
(order (command (检查图书编号 ?图书编号 ?结果))))
;;;检查图书编号: 若图书编号错误,输出错误信息,转到扫描图书编号
(response (command (检查图书编号 ?图书编号 ?结果))
(检查图书编号 ?图书编号 false)
(output 0 "图书编号错误,请重复扫描:")
(order (command 扫描图书编号)))
;;;检查图书编号: 若图书编号正确,转到扫描借阅证编号
(response (command (检查图书编号 ?图书编号 ?结果))
(检查图书编号 ?图书编号 true)
(order (command 扫描借阅证编号)))
;;;扫描借阅证编号: 从端口1输入借阅证编号,转到检查借阅证编号
(response (command (扫描借阅证编号))
(input 1 ?借阅证编号)
(order (command (检查借阅证编号 ?借阅证编号 ?结果))))
;;;检查借阅证编号: 若借阅证编号错误,输出错误信息,转到扫描借阅证编号
(response (command (检查借阅证编号 ?借阅证编号 ?结果))
(检查借阅证编号 ?借阅证编号 false)
(output 0 "借阅证编号错误,请重复扫描:")
(order (command 扫描借阅证编号)))
;;;检查借阅证编号: 若借阅证编号正确,查询上次扫描图书编号的结果,并转到借阅
(response (command (检查借阅证编号 ?借阅证编号 ?结果))
(检查借阅证编号 ?借阅证编号 true)
(last-time (检查图书编号 ?图书编号 true))
(order (command (借阅 ?图书编号 ?借阅证编号))))
;;;借阅: 根据图书编号和借阅证编号,进行借阅,最后转到完成借阅
(response (command (借阅 ?图书编号 ?借阅证编号))
(借阅 ?图书编号 ?借阅证编号)
(output 0 (借阅 ?图书编号 ?借阅证编号))
(order (command 完成借阅)))
;;;完成借阅: 简单输出借完毕的信息
(response (command 完成借阅)
(output 0 "完成借阅"))

;;;以上完全是一个流程图的文字表示

;;;调试,假定调试端口为2,(output 2 X)为输出调试信息,这个调试信息输出所有命令
;;;不管是什么命令,都能够匹配到(command ?cmd)
(response (command ?cmd)
(output 2 "命令:")
(output 2 ?cmd))

;;;系统时间相关规则,
;;;1 每次执行命令就采集一次时间,这样每个世界状态都会对应一个真实的日期和时间
(response (command ?cmd)
(input time ?time) ;;;从time端口采集时间
(modify time(_) (time ?time)))


;;;如果需求修改了
;;;修改之一:增加借阅规则,不符合借阅规则的时候,借阅不成功,并给出原因
(response (command (借阅 ?图书编号 ?借阅证编号))
(总借阅规则检查 ?图书编号 ?借阅证编号 ?总检查结果)
(= ?总检查结果 ("通过" "通过" "通过"))
(借阅 ?图书编号 ?借阅证编号)
(output 0 (借阅 ?图书编号 ?借阅证编号))
(order (command 完成借阅)))
(response (command (借阅 ?图书编号 ?借阅证编号))
(总借阅规则检查 ?图书编号 ?借阅证编号 ?总检查结果)
(!= ?总检查结果 ("通过" "通过" "通过"))
(output 0 ?总检查结果))

;;;借阅规则1:每天每个借阅证最多借三本书
;;;借阅规则2:每个借阅证的未还书不能超过10本,否则不能再借书
;;;借阅规则3:每本书要在1个月之内归还或者续期,否则不能再借书
;;;总借阅规则:依次检查每条借阅规则,有任何一条不成立,则不成立,并给出所有违反规则的信息

;;;时态查询 日期和时间表示 (time ?年 ?月 ?日 ?时 ?分 ?秒)
(rule (today ?worlds)
(since (time _ _ _ 0 0 0) ?worlds)

;;;首先得到今天的所有世界状态,然后在其中查询有几次借阅命令
(rule (这个借阅证今天借阅了几本书 ?借阅证编号 ?数量)
(today ?worlds)
(findall ?借阅证编号 (query-in (command 借阅 _ ?借阅证编号) ?worlds) ?result)
(length ?result ?数量))
(rule (借阅规则检查 _ ?借阅证编号 ?检查结果)
(这个借阅证今天借阅了几本书 ?借阅证编号 ?数量)
(< ?数量 3)
(= ?检查结果 "通过"))
(rule (借阅规则检查 _ ?借阅证编号 ?检查结果)
(这个借阅证今天借阅了几本书 ?借阅证编号 ?数量)
(>= ?数量 3)
(= ?检查结果 "今日借阅已达到3本"))
;;;每个借阅证的未还书不能超过10本
;;;未还的书: 就是在借了之后没有还的书
(rule (借阅证未还书 ?借阅证编号 ?未还的书)
(after (借阅 ?图书编号 ?借阅证编号) ?worlds))
(not (query-in (归还 ?图书编号 ?借阅证编号) ?worlds)))
(rule (借阅规则检查 _ ?借阅证编号 ?检查结果)
(findall ?未还的书 (借阅证未还书 ?借阅证编号 ?未还的书) ?result)
(length ?result ?数量)
(< ?数量 10)
(= ?检查结果 "通过"))
(rule (借阅规则检查 _ ?借阅证编号 ?检查结果)
(findall ?未还的书 (借阅证未还书 ?借阅证编号 ?未还的书) ?result)
(length ?result ?数量)
(>= ?数量 10)
(= ?检查结果 "累计未还书已经达到10本"))
;;;每本书要在一个月内归还或者续期,否则不能再借书
;;;查询某本书未还书的借阅时间,duration谓词计算两个日期之间的差(略)
(rule (未还书的借阅时间 ?未还的书 ?借阅时间)
(last-time (command (借阅 ?图书编号 _)) ?world)
(query-in (data-time ?借阅日期) ?world)
(data-time ?现在的日期)
(duration ?借阅日期 ?现在的日期 ?借阅时间)
(rule (借阅规则检查 ?图书编号 ?借阅证编号 ?检查结果)
(once (借阅证未还书 ?借阅证编号 ?未还的书)) ;;;once是指只找到一个结果就返回
(未还书的借阅时间 ?未还的书 ?借阅时间)
(>= ?借阅时间 (00 01 00 00 00 00))
(= ?检查结果 "该借阅证至少有一本超期一个月未归还或者续借")

;;;应用所有规则计算
(rule (总借阅规则检查 ?图书编号 ?借阅证编号 ?检查结果)
(findall ?检查结果 (借阅规则检查 ?图书编号 ?借阅证编号 ?检查结果) ?总检查结果)

;;;录入
(response (command (assert ?fact))
(assert ?fact)
(output ?fact))
;;;删除
(response (command (retract ?fact))
(retract ?fact)
(output ?fact))
;;;查询
(response (command (query ?q)
(query ?q)
(output ?q)))


;;;还书(略)


banq
2012-11-05 16:49

不错,只是事实有些琐碎...呵呵。

uda1341
2012-11-05 17:11

你是说那些response?

那是因为目前还不支持顺序语句,所以每个动作都要命名

SpeedVan
2012-12-08 21:09

这FOP更像是一种领域语言,在这种强大的逻辑背后,我对其负载抱有兴趣