看武侠学编程_以九宫格为例介绍强大的声明式语言Prolog

如果要给众多编程语言分个类,你可能会把它们分成低级语言和高级语言,或者分成面向对象语言和面向过程语言。然而,更多中国程序员所不太熟悉的另外一种划分方式将会把计算机语言分成命令式声明式两大阵营。之所以说大家可能不太熟悉这种划分,那是因为我们平常所使用绝大部分语言都是命令式的。但事实上你确实也应该注意到另外一大阵营的存在。

命令式编程(ImperativeProgramming)是现今最为广泛使用的编程范型。读者所熟知的众多计算机语言,如C、C++、Java、Pascal、Basic、Python、Javascript等,都属于命令式编程语言的范畴。

与命令式编程相对立的是声明式编程(Declarative programming)。声明式编程与命令式编程有很大的不同。命令式编程是命令机器如何去做事情,这样不管你想要的是什么,它都会按照你的命令实现。声明式编程则是告诉机器你想要的是什么,让机器自己去想出如何做。(这对于用惯了命令式语言的程序员来说其实是一件非常难以想象的事情,不过后面我们会给出一个例子来演示这种“智能”)声明式编程描述目标性质,让计算机明白目标,而非流程。声明式编程不用告诉电脑问题领域,从而避免随之而来的副作用。而指令式编程则需要用算法来明确的指出每一步该怎么做。

声明式编程语言的代表有Prolog、Haskell、Erlang、Lisp等(其实还有一种大家可能更熟悉的,就是SQL语言)。我们还可以将这些语言分为两类,即函数式编程语言和逻辑式编程语言。熟悉计算机发展史的读者应该会知道,图灵采用图灵机来定义算法,而丘奇则采用Lambda演算来定义算法,而这两个定义是等价的(这也称为“丘奇-图灵论题”)。命令式编程是从图灵机的概念中延伸出来的;函数式编程则是以Lambda演算和函数的概念为基础发展而来的。当前比较流行的函数式编程语言代表非Haskell莫属。

图灵和丘奇

声明式编程语言中的另外一大阵营就是逻辑式编程语言,其中非常重要的一个代表就是Prolog语言。逻辑式编程是以德国数学家、逻辑学家戈特洛布·弗雷格(Gottlob Frege)提出的谓词演算和关系的概念为基础发展而来的。函数就是一种特殊的关系,它体现的是从输入到输出的一种单向关系,而当输入固定时,输出也唯一确定。关系并没有这些限制。从这个角度来说,逻辑式编程其实涵盖了函数式编程。

首届图灵奖的获得者,美国计算机科学家艾伦·佩利(Alan Perlis)曾言道:“如果一门计算机语言无法对你的编程思考方式产生影响,那么它就不值得你去学习”。Prolog或许就是一门非常值得你去研习的语言,因为它将完全颠覆你对于编程的既有认知。

首先,Prolog并不是一个新兴的语言,相反,它其实是一种非常古老的语言。作为历史上出现的第一个逻辑式编程语言,Prolog最初是由艾克斯-马赛大学的阿兰·科尔默劳尔(Alain Colmerauer)等人在上世纪七十年代左右开发成功的。

其次,Prolog并不是什么很高深的语言,相反,与起其他一些程序语言(例如C++、Python等)相比, Prolog是更加容易理解的语言。如果你从来没有接触过计算机编程,那么恭喜你,你将很容易的进入Prolog的世界。如果你已经是其他命令式语言的高手,你就需要完全丢弃你原来的编程思路,否则是很难掌握Prolog的。

这不禁让我想起了金庸小说中老顽童周伯通自创的左右互搏术。据说周伯通曾被黄药师囚禁于桃花岛上,因为百无聊赖,遂别出心裁想到左手与右手打架,以自愉自乐。于是便自创了这门称为左右互搏术的奇学。后来,机缘巧合之下,负伤的周伯通与小龙女被金轮法王逼入绝境。小龙女与杨过曾经双剑合璧,大败金轮法王。而彼时杨过不在身边,小龙女孤掌难鸣,周伯通得知后便将左右互搏术传于小龙女。但周伯通也坦言道,黄蓉绝顶聪明,偏偏总不能得左右互搏术之要法,反倒是郭靖资质平庸,却能一学就会。而这另外一个学会了左右互搏术的便是心如止水的小龙女。最终小龙女一人分饰两角,使出玉女剑法,成功击溃了金轮法王。

说了这么多,最后我们以求解九宫格为例来演示Prolog如何能够智能地完成任务。在武侠小说《射雕英雄传》中有这样一个桥段。隐士瑛姑终日里苦修奇门异术,不想却被一道算题所困,虽百思而不得其解。问题最终被天资聪颖的黄蓉轻而易举的破解。九宫格是一种古老的数学游戏,它要求在三纵三横的一个矩阵中,填入从1到9这九个数字,并且纵向、横向、斜向上的三个数字之和皆相等。类似的问题在数学上被称为幻方。九宫格用现在的语言来描述,就是一个3×3的幻方问题。

如果你使用C++或者Python来编程,你会如何解决这个问题。如果我不告诉你所谓的“九宫格口诀”的话,你所想的事情当然是一步一步告诉计算机还如何做。事实上,即使我告诉你口诀 你也还是要让计算机根据口诀来一步一步的执行。当然,因为今天我们不是来讨论命令式语言的,所以我们就不具体演示C++或Python下的代码了。下面我们给出的Prolog的实现代码。当然考虑到读者可能从未接触过Prolog,我在其中加了注释。

:- ensure_loaded(library(clpfd)).

puzzle_solution(Ls) :-
    %每行的和都相等
    test_rows(Ls),
    %九宫格中的数字不会重复
    check_difference(Ls),    sum_diagonal(Ls, Sum1),    transpose(Ls,Ts),
    %两条对角线上的和也相等
    sum_diagonal(Ts, Sum1),
    %每列的和都相等
    test_rows(Ts).

sum_diagonal([[H|_]|[]], H).
sum_diagonal([[H|_]|Ls], Sum) :-
    remove_heads(Ls, X),
    sum_diagonal(X, Sum0),
    Sum is H + Sum0.

remove_heads([ ],[ ]).
remove_heads([[_|T]|Rows],[T|X]) :- remove_heads(Rows,X).

test_rows([]).
test_rows([[]]).
test_rows([[_|_]]).
test_rows([X,Y|Ls]) :-
    initialize(X), initialize(Y),
    sum_list(X, S), sum_list(Y, S),
    test_rows([Y|Ls]).

check_difference(Ls) :- append(Ls, L), is_set(L).

%每个格都是从1到9中的一个整数
initialize([]).
initialize([H|T]):-
    H in 1..9, label([H]),
    initialize(T).

首先这段代码显然是简短的、简单的。我们根本没有告诉计算机该怎么做,我们只是说现在我们有一个九宫格,并要求:(1)每个格都是从1到9中的一个整数;(2)九宫格中的数字不会重复; (3)每行的和都相等;(4)每列的和都相等;(5)两条对角线上的和也相等。

是的,其实我们什么也没做,只是告诉计算机我们的要求,然后让计算机自己去想该怎么做。而且计算机确实做到了,如下图所示。注意那个false并不是错误的意思。由于九宫格的答案不是唯一的,尽管Prolog会把所有的答案都求出来,但是为了演示,我们还是希望它的解空间有一定限制。于是我们规定了其中两个值2和5。注意此处矩阵是用一个相当于数组的数组的形式来表示的。然后第一次执行,Prolog给出了一个答案,由于我们只想要一个答案就好,所以我们就输入了一个句号,表示OK可以,不用再显示其他答案了。第二次执行,在Prolog给出一个答案后,我们想问还有没有其他答案,所以我们用了一个分号,分号的意思就是问计算机还有没有其他的答案。Prolog回答我们说还有,所以它又给出了一个答案。(事实上这两个答案是互为转置的矩阵)当我们用分号再次询问还有没有更多答案时,Prolog回答我们说“已经没有更多答案了”,所以它返回一个false,所以false的意思就是没有更多答案了

是不是顿时感觉Prolog很强大!事实上,Prolog还有一个更厉害的名字,叫人工智能语言,它在编写专家系统和人工智能应用方面非常非常常用,以后有机会,博主再奉上更多更炫的Prolog

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-09 01:22:34

看武侠学编程_以九宫格为例介绍强大的声明式语言Prolog的相关文章

我给女朋友讲编程分享篇--看我姐和我女朋友如何学编程

有两天没有更新文章了,真是惭愧啊.前天,我想写写有关网站配色.美工方面的一些内容,查了很久,都没有找到满意的,本人也是程序员,没做过美工,所以对这方面确实很欠缺,希望哪位美工看到了,可以给我们程序员专门写一个系列的文章,叫<我教程序员学美术>,然后用最简单的.最生动的内容写出来,一定有很多程序员喜欢看.如何真得火了,到时候出书了,我一定买一本,捧捧场,哈哈. 昨天,搜了一下,如何注册免费空间和域名,本来是想注册一个免费的域名,申请一个免费的空间,自己可以更新文件的那种,结果,找了好几个,都不满

学编程新手必看文章

1.把C++当成一门新的语言学习(和C没啥关系!真的.): 2.看<Thinking In C++>,不要看<C++变成死相>: 3.看<The C++ Programming Language>和<Inside The C++ Object Model>,不要因为他们很难而我们自己是初学者所以就不看: 4.不要被VC.BCB.BC.MC.TC等词汇所迷惑--他们都是集成开发环境,而我们要学的是一门语言: 5.不要放过任何一个看上去很简单的小编程问题--他们

从零学编程1-写一封情书

一哥们闲暇之余想学编程,博主作为"会装系统的人"自然脱不了干系,这哥们名字叫鹰,初中文化,对于电脑的认识属于只会上网听歌看电影,差点忘了他强调过CF玩的不错. 那就教起吧. 主人公两枚: 鹰:从零学编程的哥们 我:从零教编程的作者 !!注意为了便于新手理解,使用大量的便于理解的语句,不代表本人知识水平.我怎么会告诉你Windows启动过程呢.(- o -)~ 开始我们的故事 我:今天让我们写一封电子情书. 鹰:我听说过,但是网上说得太复杂了- 我:会非常简单的.先下载个编程工具.就用我

17岁开始学编程,晚么?

刚在伯乐在线上看到一篇文章: 有位年轻的童鞋在 Quora 提问,“如果想成为一名顶级程序员,17岁开始学编程晚么?”FB 前程序员 Don Pinkus 针对这个问题,分享他从 22 岁开始起学习编程的经历. 看完他的分享,截取对自己有帮助部分马克一下,查看原文(http://blog.jobbole.com/85548/) 如果你现在就希望自己成为一名工程师,那么以下就是你的任务清单: 1. 到w3schools.com网站上学习HTML和CSS.2. 思考一下你想做一个什么样的网站.已经有

我为什么学编程?

学习编程认真的算起来已经有2个多月了,实际上只有一个多月时间是认真学,其余时间是找借口或者说是心情不好,而不去学.总的来说已经是开始入门了.前几天一直以为自己笨,学了很长时间什么都没学会.可是昨天无意间看了学习Java的视频,感觉也没有那么难(我是从c语言开始学起的,看的是郝斌的视频和在网上买的C Primer Plus(第五版)中文版),除此之外,还发现那个老师打的代码不 规范,至少是不漂亮!!! 好了,言归正传!我在上初中时,我的一个远房叔叔就送了我一本谭浩强写的<C语言程序设计>,可是我

0502《与孩子一起学编程》读书笔记3

1.主要有两种循环,计数循环和条件循环.前者一般叫做for循环,后者一般叫做while循环.要停止一个失控循环的Python程序,只需要按下Ctrl C. 2.跳出循环语句有两种,break和continue.前者完全终止该次循环,后者是提前跳转到循环的下一次迭代. 3.附带目前查询的资料: ----python函数库:http://www.lfd.uci.edu/~gohlke/pythonlibs/ ----<与孩子一起学编程>网址:http://www.manning.com/sande

我教女朋友学编程Html系列(6)—Html常用表单控件

做过网页的人都知道,html表单控件十分重要.基本上我们注册会员.登录用户,都需要填写用户名.密码,那些框框都是表单控件. 本来今天就想写一些常用的html表单控件,于是开始搜资料,找到了一个网页,作者的写作思路和我的基本相同,不过不足的是缺少效果图. 我打算结合着这位仁兄的文章补充一下,增加一些效果图,另外把一些新内容也补充进去,原文的地址是: HTML表单(Forms) 我站在这位仁兄的肩膀上写作,再增加一些东西,配上一些图,我想,效果应该很好,接着就跟着我来学习吧. HTML表单(Form

为什么要学编程呢?

为什么要学编程?  不知道大家有没有感受到云计算的威胁?我已经深深的感受到了来自公有云的威胁,虽然国内云环境还不成气候,但威胁无时不在. 按照当前的发展趋势,运维,或者说中级运维的需求会越来越少,为什么会这样?因为随着自动化程度的提高,尤其像docker这样的容器技术的发展,更多的运维沦为操作工,而这是初级运维的事,我花5k请一个应届生能操作得很好,而且还听话,我干嘛要花15k去雇你. 然而,也并非所有运维都沦为操作工,那些在某一领域有深入研究的专家,在需要他的地方,永远是块宝,这样的人,无须我

学编程?重要?!

学会编程益处多多. 学会编程有很多好处.除了明显的如可以创建网站和web应用,在你找工作的过程中,即使你找的不是天天写码的工作,拥有编程技能也可能会让你脱颖而出. 本文摘编译自Skillcrush,作者LAURENCE BRADFORD. 在探索编码技能能够为你带来所有工作的可能性之前,先说下我的一个例子. 我获得了一个与代码无关的工作,却是因为我会写代码.这个工作机会大部分是与我的技能和协作或营销有关. 举 个我为Josh Owens工作的例子.Josh是Meteor.js社区很有名的一个人物