??xml version="1.0" encoding="utf-8" standalone="yes"?>久久九九有精品国产23百花影院,人妻无码中文久久久久专区,国产精品久久久久久福利漫画http://www.shnenglu.com/cuigang/category/5861.html(define (coding) (coding)) zh-cnMon, 19 May 2008 12:56:50 GMTMon, 19 May 2008 12:56:50 GMT60计算U学数学理论谈Q{Q?/title><link>http://www.shnenglu.com/cuigang/articles/46229.html</link><dc:creator>cuigang</dc:creator><author>cuigang</author><pubDate>Thu, 03 Apr 2008 17:12:00 GMT</pubDate><guid>http://www.shnenglu.com/cuigang/articles/46229.html</guid><wfw:comment>http://www.shnenglu.com/cuigang/comments/46229.html</wfw:comment><comments>http://www.shnenglu.com/cuigang/articles/46229.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/cuigang/comments/commentRss/46229.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/cuigang/services/trackbacks/46229.html</trackback:ping><description><![CDATA[<span style="font-size: 10pt; font-family: Tahoma;"> 计算从其诞生之日P它的主要d是q行各种各样的科学计。文档处理, <br> 数据处理Q图像处理,g设计QY件设计等{,都可以抽象ؓ两大c:数D与?<br> 数D。作为研I计机U学技术的人员Q我们大都对计算数学Ҏ个计机U学?<br> 重要性有一些了解。但是数学对我们q些专业的研I和应用人员I竟有多大的用处呢? <br> 我们先来看一下下面的一个流E图Q?<br> <br> ─→数学模型─?#8594;数D方法──┐          <br> │         ?#8594;E序设计 <br> ?#8594;非数D方法─?nbsp;       ?<br>                                            ↓ <br>                                   ~译E序Q求计算l果 <br> <br> <br>       上图揭示了利用计机解决U学计算的步骤,实际问题转换为程序,要经q一个对 <br> 问题抽象的过E,建立起完善的数学模型Q只有这P我们才能建立一个设计良好的E?<br> 序。从中我们不隄数学理论对用计机解决问题的重要性。下面我们将逐步?<br> 开对这个问题的讨论?<br> <br>       计算机科学的数学理论体系是相当庞杂的Q笔者不敢随意划分,参考计机U学?<br> 论的学科体系Q我们谈及的问题主要涉及Q数D,L数学Q数论,计算理论四大 <br> 方向?<br> <br> [一]数D(Numerical ComputationQ?<br> <br> 主要包括数值分析学、数学分析学、线性代数、计几何学、概率论与数理统计学?<br> <br>       数值分析学又常被称方法学Q是计算理论数学非常重要的一个分支,主要?<br> I数值型计算。研I的内容中首先要谈谈数D的误差分析Q误差是衡量我们的计?<br> 有效与否的标准,我们的算法解决问题如果在误差允许的范围内Q则法是有效的Q否 <br> 则就是一个无效的问题求解。另外就是数值DQ它研究关于如何使用Ҏ数D的 <br> 函数来近似地代替L函数的方法与q程。感觉应用比较广的不得不提切雪比夫D?<br> qxD了。笔者曾l尝试过的就是通过最佛_^斚wDq行曲线的拟合,开发工具可?<br> 选择VC++或者Matlab。插值函数是另外一个非帔R要的斚wQ现代的计算机程序控制加 <br> 工机械零ӞҎ设计可给出零件外形曲U的某些型值点Q加工时走刀方向及步敎ͼ?<br> 要通过插值函数计零件外形曲U及其他点函数倹{至于方E求栏V线性方E组求解Q?<br> 一般的计算性程序设计问题都会多多少的涉及一些,我们q里׃赘述了。关于数?<br> 分析学的一个学习误区就是仅仅学习理论知识,而很隑֒E序设计l合hQ实际上?<br> q上面的Q大家已l能够初步地认识到这个学U是应当与程序设计紧密联pL能够 <br> 体现它的重要性的。关于理论的学习Q推荐华中科技大学李庆扬老师的《数值分析》?<br> 然而理论学习毕竟是个过E,最l的目标q是要用于程序设计解军_际的计算问题Q向 <br> q个方向努力的书c还是挺多的Q这里推荐大安{教育出版社QCHEPQ和施普林格?<br> 版社(Springer)联合出版的《计方法(Computational MethodsQ?华中理工大学?<br> 学系写的Q现华中U技大学Q,q方面华U大做的工作在国内应是比较多的Q而个?<br> 认ؓ以这本最好,臛_E序设计斚w涉及了:L数学函数的求|方程求根Q线性方 <br> E组求解Q插值方法,数值积分,场微分方E数值求解?<br> <br> <br>      数学分析学很多学校在q些q已l替代高{数学被安排C本科教学当中。原因是 <br> 很简单的Q高{数学虽然也是非常有用的工程数学Q介l的问题Ҏ也被q泛的应用, <br> 但是正如大家所知道的,高等数学不太严格的说Q基本上是偏向于计的数学分析Q?<br> 当然省去了数学分析非常看重的推理证明Q然而我们认一部分正是我们最需要的?<br> q对我们培养良好的分析能力和推理能力极有帮助。我的Y件工E学导师北工大数理学 <br> 院的王A华先生就曄教导q我们,数学pȝ学生到Y件企业中大多作Y件设计与分析 <br> 工作Q而计机pȝ学生做初U程序员的居多,原因在于数学系的学生分析推理能?<br> Q从所受训l的角度上要q远在我们^均水q之上。谈到这斚w的书c,公认北京大学 <br> 张筑生老师的《数学分析新讌Ӏؓ最好。张{生教授一生写的书q不太多Q但是只要是 <br> 写出来的每一本都是本领域内的CQ这本当然更昄Z。这U老书看v来不仅是?<br> 传授你知识,而是在让你体会科学的Ҏ与对事物的认识方法。现在多用的g是复?<br> 大学的《数学分析》,高等教育出版CQ也是很好的教材。但关于如何d用从中获 <br> 得的推理证明能力Q我们在遇到具体问题的时候,可以在今后的文章详细讨论?<br> <br>       U性代数是我们在工U本U学习的必修评Q似乎大家找不到到底q个有什么用Q?<br> 其实很明显,U性代C为工E数学的重要分支Q在计算机领域的研究有相当广泛的?<br> 用。最为突出的可以谈谈数组和矩늚相关知识Q?<br> <br> ?#8592;—④ <br> ↑\      ?<br> ↓     \,↓ <br> ?#8592;—③ <br> <br> 令aij=1,表示从i市到j市有1条航U?<br> 令aij=0Q表CZi市到j市没有单航U?<br> 则图可用矩阵表示Q?<br> <br>                ?nbsp;          ?<br>                ? 1 1 0 ?<br>                ? 0 0 0 ?<br> A= (aij) = ? 1 0 0 ?<br>                ? 0 0 0 ?<br>                ? 0 1 0 ?<br>                ?nbsp;          ?<br> <br>       我们可以采用E序设计实现q个问题Q如果辅以权|可以转化为最短\径的问题 <br> Q再复杂化一点还可以转化为具有障物的最短\径问题,q就会涉及一些如Dijkstra <br> 法{高U程序设计算法话题。这些都依靠着数组、矩늚基本知识。数l的应用主要 <br> 在图像处理以及一些程序设计理论。矩늚q算领域极ؓq泛Q比如在计算机图形学?<br> 中曲U曲面的构造,囑փ的几何变换,包括q移、镜像、{|、羃放。在高囑փ问题 <br> 更有q泛应用Q例如在囑փ增强技术,投媄技术中的应用?<br> <br>       计算几何学研I的是几何外形信息的计算C。包括几何查找、多边Ş、凸包问 <br> 题、交与ƈ、几何体的排列、几何拓扑网l设计、随机几何算法与q行几何法。它?<br> 成了计算机图形学中的基本法Q是动画设计Q制造业计算助设计的基础。如果从 <br> 事这斚w的深入研IӞ可以参考中国计机学会周培德先生的《计几何——算法分?<br> 与设计》?<br> <br>       概率Z数理l计学是q个领域最后一门关键的评。概率论部分提供了很多问?<br> 的基本知识描qͼ比如模式识别当中的概率计,参数估计{等。数理统计部分有很多 <br> 非常l典的内容,比如伪随机数、蒙特卡|法、回归分析、排队论、假设检验、以及经 <br> 典的马科夫过E。尤其是随机q程部分Q是分析|络和分布式pȝQ设计随机化法?<br> 协议非常重要的基?<br> <br> 二]L数学QDiscrete MathematicsQ?<br> <br> 随着计算机科学的出现与广泛应?Z发现利用计算机处理的数学对象与传l的分析 <br> 有明昄区别Q分析研I的问题解决Ҏ是连l的Q因而微分,U分成ؓ基本的运; <br> 而这些分支研I的对象是离散的Q因而很有Zq行此类的计。h们从而称q些?<br> 支ؓ"L数学"。离散数学经q几十年发展Q方向上基本上稳定下来。当然不同时期还 <br> 有很多新内容补充q来。就学科方向而言Q一般认为,L数学包含Q集合论、逻辑?<br> 、代数学、图论、组合学?<br> <br>       逻辑学(LogicsQ我们主要指数理逻辑QŞ式逻辑在推理问题中也有比较q泛的应 <br> 用。(比如我们学校qؓ此专门开设了选修评Q这斚w的参考推荐中U院软g所陆钟 <br> 万教授的《面向计机U学的数理逻辑》。现在可以找到陆钟万教授的讲译ֽ像,http <br> ://www.cas.ac.cn/html/Dir/2001/11/06/3391.htm。ȝ来说Q学集合/逻辑一定要?<br> 在理解的高度上去思考相关的问题。集合论QSet TheoryQ和逻辑学构成了计算机科?<br> 最重要的数学问题描q方式?<br> <br>       代数学(AlgebraQ包括:抽象代数、布代数、关pM数、计机代数 <br> <br> Q?Q抽象代敎ͼAbstract AlgebraQ研I的主要内容늛、环、域。抽象代表的?<br> 研I对象的本质提炼出来Q加以高度概括,来描q其形象?#8220;Ƨ式?#8221;是在将整数 <br> 和多式的一些相同的特点加以l合提炼引入的。抽象代数提供的一些结Zؓ我们研究 <br> 一些具体问题时所需使用的一些性质提供了依据。推荐一个最单的Q最Ҏ学的材料 <br> Q?a target="_blank">http://www.math.miami.edu/~ec/book/q本《Introduction</a> to Linear and Abstra <br> ct Algebra》非帔R俗易懂Q而且把抽象代数和U性代数结合v来,对初学者来说非?<br> 理想?<br> <br> Q?Q布代敎ͼBoolean AlgebraQ是代数pȝ中最为基的部分,也是最核心的基?<br> 理论。主要包括了集合的基本概念与q算Q自对偶的公理系l。是数据表示的重要基 <br> 。相信大安很清楚它的重要性?<br> <br> Q?Q关pM敎ͼRelational AlgebraQ应用也是极为广泛,比如数据库技术中的关pL <br> 据库的构建就要用到关pM数的相关理论?<br> <br> Q?Q计机代数QComputer AlgebraQ大家可能比较生疏,其实它研I的主要内容x <br> 围绕W号计算与公式演展开的。是研究代数法的设计、分析、实现及其应用的学科 <br> 。主要求解非数D,输入输出用代数符可C。计机代数的开发语a主要有:AL <br> TRAN,CAMAL,FORMAL。主要应用于Q射影几何,工业设计Q机器h手臂q动设计?<br> <br>       图论QGraph TheoryQ主要研I的内容包括Q图的基本概c基本运、矩阵表C?<br> Q\径、回路和q通性,二部图、^面图Q树Q以及网l流。图论的应用领域太过q泛 <br> Q仅举两个例子:比如在计机|络拓扑囄设计与结构描qCQ就必须用到相当多的 <br> 囄l构和基本概c关于网l流更是在电网l与信息|络的流量计当中广泛应?<br> 。树的相兛_用则无须多言了?<br> <br>       l合学(CombinatoricsQ有两部分单独的研究领域Q组合数学与l合法。组合学 <br> 问题的算法,计算对象是离散的、有限的数学l构。从Ҏ学的角度Q组合算法包括算 <br> 法设计和法分析两个斚w。关于算法设计,历史上已lȝZ若干带有普遍意义?<br> Ҏ和技术,包括动态规划、回溯法、分支限界法、分L、贪心法{。应用是相当q?<br> 泛的,比如旅行商问题、图着色问题、整数规划问题。关于组合数学,主要研究的内Ҏ <br> Q鸽巢原理、排列与l合、二式pLҎ原理及应用,递推关系和生成函数、特D计 <br> 数序列、二分图中的匚w、组合设计。推荐Richard A.Brualdi的《Introductory Comb <br> inatorics》作为参考?<br> <br> [三]数论QNumber TheoryQ?<br> <br>      数论q门学科最初是从研I整数开始的Q所以叫做整数论。后来更名ؓ数论。它包括 <br> 以下几个分支Q?<br> <br>      初等数论是不求助于其他数学学U的帮助Q只依靠初等Ҏ来研I整数性质的数论分 <br> 支。比如在数论界非常著名的“中国剩余定理”Q就是初{数Z很重要的内容。对?<br> E序设计来说q部分也是相当有价值的Q如果你对中国剩余定理比较清楚,利用它,?<br> 可以一U表辑ּl过单的转换后得出另一U表辑ּQ从而完成对问题分析视角的{ <br> 换?<br> <br>      解析数论是用数学分析作为工h解决数论问题的分支。是解决数论中比较深刻问 <br> 题的强有力的工具。我国数学家陈景润在试解决“哥d巴赫猜想”问题中用的是 <br> 解析数论的方法。以素数定理为基解决计算素数的问题及其算法实现应是我们多多关 <br> 注的?<br> <br>       代数数论是把整数的概忉|q到一般代数数域上去,建立了素整数、可除性等概念 <br> 。程序设计方面涉及的比较多的是代数曲U的研究Q比如说椭圆曲线理论的实现?<br> <br>       几何数论研究的基本对象是“I间格网”。空间格|就是指在给定的直角坐标pM <br> Q坐标全是整数的点,叫做整点Q全部整Ҏ成的l就叫做I间格网。空间格|对计算 <br> 几何学的研究有着重大的意义。几何数论涉及的问题比较复杂Q必d有相当的数学?<br> 才能深入研究?<br> <br>       ȝ说来Q由于近代计机U学的发展,数论得到了广泛的应用。比如在计算Ҏ <br> 、代数编码、组合学理论{方面都q泛使用了初{数围内的许多研I成果;现在?<br> 些国家应?#8220;孙子定理”来进行测距,用原根和指数来计离散傅里叶变换{。如果你 <br> 曄pȝ的学习过数论法Q你会发现这个分支学U研I的一些基本问题对E序设计?<br> 相当有用的,比如说素数问题、素性测试、因子分解、最大公U数、模取幂q算、求?<br> 同余U性方E。其中的很多问题都是E序设计的基本问题。但q些问题都不能小视,?<br> 个例子来说吧Q关于求最大公U数的程序,W者曾l尝试的可以采用@环语句结构和 <br> 递归l构。另外,以大素数为基的密码体pȝ建立是近些年数论法q泛应用的一?<br> 重要的原因。原理是大素数的乘积重新分解因数十分困难。RSA公钥加密pȝ的构建就?<br> Zq个原理的(三位发明人因此也获得?002q美国计机协会颁发的图灵奖Q?<br> <br> <br> 四]计算理论QTheory of ComputationQ?<br> <br>       涉及的内ҎU学计算非常重要的一部分分支Q也是大家研I相当多的一部分。主 <br> 要包括:法学,计算复杂性,E序理论?<br> <br>      法学(AlgorithmsQ在计算机科学理Z有着举轻重的地位。是解决很多数?<br> 型,非数值型问题的基。记得一ơ学校接收招标项目,很多中小型Y件厂商都无法?<br> 成一个Y件的功能模块Q就是因为当时他们对一个具体问题的法不能做出正确的抽?<br> Q最后由我们学校数理学院的一支Y件团队承担了q项dQ他们的最l报告体现出?<br> Q问题的解决{略只有通过人工经元网l的反向传播法。可见在比较有深度的E序 <br> 设计中,法的重要性更为突出。学习算法学要有一个长期的理论和实늚q程。遇?<br> 一个具体算法问题时,首先要通过自己描述的数学抽象步骤,看看自己以前有没有处理过 <br> q种问题。如果没有,很可能这个问题是多个法的综合,或者是需要我们自己去构?<br> 法。这需要我们有扎实的算法功底,Z打好q个功底Q推荐两套圣l的书c首 <br> 先是Thomas H.Cormen{著的《Introduction to Algorithms》。对法学习而言Q这一 <br> 本内容相当的全面。再׃点的是大家作ؓ常识都知道的《The Art of Computer Pr <br> ogramming》,目前已经出版3册。两本书的h值大家应当都是清楚的?<br> <br>       计算复杂性研I的内容很广Q其中包括NP完全性理论,可计性理论,自动机理?<br> QŞ式语a理论Q包括广泛应用于~译原理领域的文法,q包括Petri|论的相兛_容) <br> 以及大家熟知的复杂性度量。时间复杂度、空间复杂度的计是度量法非常重要的参 <br> 敎ͼ也是我们衡量E序优劣E度的重要依据?<br> <br>       E序理论QTheory of programsQ包含了形式语义学,E序验证和ƈ发模型的研究 <br> 。关于程序验证学习的重要性大安很清楚,学习的方法自然也是多多结合具体的问题 <br> d析。关于ƈ发模型,主要研究的就是进E代敎ͼ通信pȝ演算Q通信序q程。这 <br> 部分是研I操作系l理Z实现的重要基?<br> <br>       按照计算机科学数学理论的架构来谈了各斚w的内容和一些应用,下面我们再单?<br> 来看一些上面没有涉及到的学U与q些理论的具体结合情况: <br> <br> <br>       设计斚w的应用刚才谈的很多,我只再说说数据库原理与技术,q方面用到的重要 <br> 数学基础主要包括Q集合论Q二元关pd其推理(其是研I关pL据库Q,研究数据 <br> 分布与数据库l构又涉及相当多的图论知识?<br> <br>       计算机科学的发展有赖于硬件技术和软g技术的l合。在设计g的时候应当充?<br> 融入软g的设计思想Q才能ɼg在程序的指挥下发挥极致的性能。在软g设计的时?<br> 也要充分考虑g的特点,才能冲破软g效率的瓶颈。达到硬件和软g设计的统一Q严 <br> 格的说这q不LQ一般的E序设计者很隑ְq样的思想贯穿在其E序设计当中。仅?<br> 个简单的例子Q我们在写一些C语言的程序,必要的时候都会采取内嵌一D|~指令,q?<br> 是比较充分地考虑了硬件的工作情况Q从而能够提高程序运行的效率。所以我们也?<br> 必要了解一些硬件的基础知识。关于学习硬件的时候常会用到的基本数学思想也是相当 <br> 多的Q拿电\基础与模拟电路来_我们q常要利用多元函数Q不{式计算q行甉| <br> 电压的计。能量的计算q常常涉及微U分学的很多计算。在数字电子技术当中(有时 <br> 也称数字逻辑学)数理逻辑Q尤其是逻辑演算部分q用相当q泛Q数制{换更是非帔R <br> 要的基础Q各U数字电路参数的计算则是多元函数Q不{式的计解决的问题?<br> <br>       从事计算机硬件程序设计的E序员,则不可回避的是数字信号处理。这门科学所 <br> 用到的数学基主要有:三角函数、微U分、高ơ方E求解、数值DQ傅里叶变换?<br> 在o波器的设计当中还会用到矩阵运。笔者曾l研I过一个VC++环境下开发的滤L?<br> 的模拟YӞ是利用莱文?杜宾递推法Q在较大规模的矩阵运基上进行的。当 <br> Ӟ开发的环境不一定是q个Q你也可以选择MATLAB或者纯C语言~译器。如果我们不?<br> 解相关的数学基础Q不要说E序设计Q就是建立q算模型都是相当困难的?<br> <br>       一些周围的同学和一些在职的E序员,大家l过一D|间的学习Q普遍都觉得数学 <br> 对学习计机和研I计机E序设计{问题来说非帔R要,但是又苦于无从下手。上?<br> 比较全面地谈及了计算机科学数学理论的相关内容。需要特别指明的是,我们研究问题 <br> 的精力是有限的,如果您是在校的计机pd生,则可以对上面的方斚w面都有所涉及 <br> Q以试计算数学q个强大的理论工兗ؓ今后的工作奠定一个坚实的基础。但是如?<br> 您研I的是比较具体的工作Q我们ƈ不推荐您研究所有的内容Q最好的Ҏ是对上?<br> 的数学基都有些了解,然后遇到具体工作Q需要哪部分内容Q再q行深入的学习与?<br> I。这样针Ҏ比较强的学习效果是会比较显著的。对于上面推荐的一些参考材料,?<br> 非你要花相当长的一D|间来提高你的计算机数学理论。否则也没必要每一,每一?<br> 都字字精读,q是那个原则Q按需索取其中的内宏V学习的Ҏ描述h׃句话Q结 <br> 合具体的问题Q深入的理解数学理论知识Q将理论E序化,试用程序设计实现理论原 <br> 理。达到这LE度Q问题基本上都可以解决的 <br></span><img src ="http://www.shnenglu.com/cuigang/aggbug/46229.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/cuigang/" target="_blank">cuigang</a> 2008-04-04 01:12 <a href="http://www.shnenglu.com/cuigang/articles/46229.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(ZT) Scheme 语言概要http://www.shnenglu.com/cuigang/articles/39398.htmlcuigangcuigangSun, 23 Dec 2007 12:43:00 GMThttp://www.shnenglu.com/cuigang/articles/39398.htmlhttp://www.shnenglu.com/cuigang/comments/39398.htmlhttp://www.shnenglu.com/cuigang/articles/39398.html#Feedback0http://www.shnenglu.com/cuigang/comments/commentRss/39398.htmlhttp://www.shnenglu.com/cuigang/services/trackbacks/39398.html Scheme 语言是LISP语言的一个方a(或说成变U?Q它诞生?975q的MITQ对于这个有q三十年历史的编E语a来说Q它q没有象C++QjavaQC#? 样受到商业领域的青睐Q在国内更是显ؓ人知。但它在国外的计机教育领域内却是有着q泛应用的,有很多h学的W一门计机语言是Scheme语言?

作ؓLisp 变体QScheme 是一门非常简z的计算语言Q用它的编Eh员可以摆pa本n的复杂性,把注意力集中到更重要的问题上Q从而语言真正成ؓ解决问题的工兗本文分Z?下两部分来介l?scheme 语言?/p>

一QScheme语言的特?/h2>

Scheme 语言是LISP语言的一个方a(或说成变U?Q它诞生?975q的MITQ对于这个有q三十年历史的编E语a来说Q它q没有象C++QjavaQC#? 样受到商业领域的青睐Q在国内更是显ؓ人知。但它在国外的计机教育领域内却是有着q泛应用的,有很多h学的W一门计机语言是Scheme语言?/p>

它是一个小巧而又强大的语aQ作Z个多用途的~程语言Q它可以作ؓ脚本语言使用Q也可以作ؓ应用软g的扩展语a来用,它具有元语言Ҏ,q有很多独到的特?以致于它被称为编E语a中的"皇后"?/p>

下面是洪峰对Scheme语言的编E特色的归纳Q?/p>

  • 词法定界QLexical ScopingQ?/li>
  • 动态类型(Dynamic TypingQ?/li>
  • 良好的可扩展?/li>
  • N归QTail RecursiveQ?/li>
  • 函数可以作ؓD?/li>
  • 支持一的计算q箋
  • 传D用(passing-by-valueQ?/li>
  • 术q算相对独立

本文的目的是让有~程基础Q那怕是一点点Q的朋友能尽快的掌握Scheme语言的语法规则,如果您在d本文后,发现自己已经会用Scheme语言了,那么我的目的pC?/p>

二.Scheme语言的标准与实现

R5RS (Revised(5) Report on the Algorithmic Language Scheme)

Scheme语言的语法规则的W?ơ修正稿Q?998q制定,即Scheme语言的现行标准,目前大多数Scheme语言的实现都达到或遵@此标准,q且几乎都加入了一些属于自q扩展特色?/p>

Guile (GNU's extension language)

Guile是GNU工程的一个项目,它是GNU扩展语言库,它也是Scheme语言的一个具体实玎ͼ如果你将它作Z个库打包Q可以把它链接到你的应用E序中去Q你的应用E序h自己的脚本语aQ这个脚本语a目前是Scheme语言?/p>

Guile可以在LINUX和一些UNIXpȝ上运行,下面是简单的安装q程Q?/p>

下蝲guile-1.6.4版,文g名ؓguile-1.6.4.tar.gzQ执行下面的命oQ?/p>

tar xvfz guile-1.6.4.tar.gz
cd guile-1.6.4
./configure
make
make install

如此Q即可以执行命oguileQ进入guile>提示W状态,输入调试SchemeE序代码了,本文的所有代码都是在guile下调试通过?/p>

其它实现

除了Guile外,Scheme语言的实现还有很多,如:GNU/MIT-SchemeQ? SCIQScheme48QDrScheme{,它们大多是开源的Q可以自׃载安装用,q且跨^台的实现也很多。你会发现既有象basic? Scheme语言解释器,也有Scheme语言~译成C语言的编译器Q也有象JAVA那样Scheme语言代码~译成虚拟机代码的编译器?/p>

三.基本概念

注释

Scheme语言中的注释是单行注释,以分号[;]开始一直到行尾l束Q其中间的内容ؓ注释Q在E序q行时不做处理,如:

; this is a scheme comment line.

标准的Scheme语言定义中没有多行注释,不过在它的实C几乎都有。在Guile中就有多行注释,以符L?#!"开始,以相反的另一W号l合"!#"l束Q其中内容ؓ注释Q如Q?/p>

#!
there are scheme comment area.
you can write mulity lines here .
!#

注意的是Q符L?#!"?!#"一定分做两行来写?/p>

Scheme用做脚本语言

Scheme语言可以象shQperlQpython{语a那样作ؓ一U脚本语a来用,用它来编写可执行脚本Q在Linux中如果通过Guile用Scheme语言写可执行脚本Q它的第一行和W二行一般是cM下面的内容:

#! /usr/local/bin/guile -s
!#

q样的话代码在运行时会自动调用Guile来解释执行,标准的文件尾~?.scm"?/p>

?form)

?form)是Scheme语言中的最程序单元,一个Scheme语言E序是由一个或多个form构成。没有特D说明的情况?form 都由括hhQŞ如:

(define x 123)
(+ 1 2)
(* 4 5 6)
(display "hello world")

一?form 也可以是一个表辑ּQ一个变量定义,也可以是一个过E?/p>

form嵌套

Scheme语言中允许form的嵌套,q它可以轻杄实现复杂的表辑ּQ同时也是一U非常有自己特色的表辑ּ。下囄意了嵌套的稍复杂一点的表达式的q算q程Q?/p> http://www.oxsama.com/?k=data_image&p=static.d/1189119482-19692-0.rst.images/0.png

变量定义

可以用define来定义一个变量,形式如下Q?/p>

(define 变量??

如: (define x 123) Q定义一个变量xQ其gؓ123?/p>

更改变量的?/p>

可以用set!来改变变量的|格式如下Q?/p>

(set! 变量??

如: (set! x "hello") Q将变量x的值改?hello" ?/p>

Scheme语言是一U高U语aQ和很多高语言(如pythonQperl)一P它的变量cd不是固定的,可以随时改变?/p>

四.数据cd

1. 单数据类?/h2>

逻辑?boolean)

最基本的数据类型,也是很多计算a中都支持的最单的数据cdQ只能取两个|#tQ相当于其它计算a中的 TRUEQ?fQ相当于其它计算a中的 FALSE?/p>

Scheme语言中的booleancd只有一U操作:not。其意ؓ取相反的|卻I

(not #f) => #t
(not #t) => #f

not的引用,与逻辑非运操作类?/p>

guile> (not 1)
#f
guile> (not (list 1 2 3))
#f
guile> (not 'a)
#f

从上面的操作中可以看出来Q只要not后面的参C是逻辑型,其返回值均?f?/p>

数字?number)

它又分ؓ四种子类型:整型(integer)Q有理数?rational)Q实?real)Q复数型(complex)Q它们又被统一UCؓ数字cd(number)?/p>

如:复数?complex) 可以定义?(define c 3+2i) 实数型(realQ可以定义ؓ (define f 22/7) 有理数型QrationalQ可以定义ؓ (define p 3.1415) 整数?integer) 可以定义?(define i 123)

Scheme 语言中,数字cd的数据还可以按照q制分类Q即二进Ӟ八进Ӟ十进制和十六q制Q在外观形式上它们分别以W号l合 #b? #o?#d?#x 来作C数字进制类型的前缀Q其中表C十q制?d可以省略不写Q如Q二q制?#b1010 Q八q制? #o567Q十q制?23?#d123Q十六进制的 #x1afc ?/p>

Scheme语言的这U严格按照数学定理来为数字类型进行分cȝҎ可以看出Scheme语言里面渗透着很深的数学思想QScheme语言是由数学家们创造出来的Q在q方面表现得也比较鲜明?/p>

字符?char)

Scheme语言中的字符型数据均以符L?"#\" 开始,表示单个字符Q可以是字母、数字或"[ ! $ % & * + - . / : < = > ? @ ^ _ ~ ]"{等其它字符Q如Q? #\A 表示大写字母AQ?\0表示字符0Q? 其中Ҏ字符有:#\space 表示I格W和 #\newline 表示换行W?/p>

W号?symbol)

W号cd是Scheme语言中有多种用途的W号名称Q它可以是单词,用括hh的多个单词,也可以是无意义的字母l合或符L合,它在某种意义上可以理解ؓC中的枚Dcd。看下面的操作:

guile> (define a (quote xyz))  ;  定义变量a为符L型,gؓxyz
guile> a
xyz
guile> (define xyz 'a) ; 定义变量xyz为符L型,gؓa
guile> xyz
a

此处也说明单引号' 与quote是等LQƈ且更单一些。符L型与字符串不同的是符L型不能象字符串那样可以取得长度或改变其中某一成员字符的|但二者之间可以互相{换?/p>

2. 复合数据cd

可以说复合数据类型是由基本的单数据类型通过某种方式加以l合形成的数据类型,特点是可以容U_U或多个单一的简单数据类型的数据Q多数是Z某一U数学模型创建的?/p>

字符?string) 由多个字W组成的数据cdQ可以直接写成由双引hL内容Q如Q?hello" 。下面是Guile中的字符串定义和相关操作Q?/p>

guile> (define name "tomson")
guile> name
"tomson"
guile> (string-length name) ; 取字W串的长?br>6
guile> (string-set! name 0 #\g) ; 更改字符串首字母(W?个字W?为小写字母g (#\g)
guile> name
"gomson"
guile> (string-ref name 3) ; 取得字符串左侧第3个字W(?开始)
#\s

字符串还可以用下面的形式定义Q?/p>

guile> (define other (string #\h #\e #\l #\l #\o ))
guile> other
"hello"

字符串中出现引号时用反斜U加引号代替Q如Q?abc\"def" ?/p>

点对(pair)

我把它译?点对"Q它是一U非常有的cdQ也是一些其它类型的基础cdQ它是由一个点和被它分隔开的两个所值组成的。Ş如: (1 . 2) ?(a . b) Q注意的是点的两ҎI格?/p>

q是最单的复合数据cdQ同是它也是其它复合数据cd的基cdQ如列表cdQlistQ就是由它来实现的?/p>

按照Scheme语言说明中的惯例Q以下我们用W号l合 "=>" 来表C辑ּ的倹{?/p>

它用cons来定义,如: (cons 8 9) =>(8 . 9)

其中在点前面的DUCؓ car Q在点后面的DUCؓ cdr Qcar和cdr同时又成为取pair的这两个值的q程Q如Q?/p>

(define p (cons 4 5))   => (4 . 5)
(car p) => 4
(cdr p) => 5

q可以用set-car! ?set-cdr! 来分别设定这两个|

(set-car! p "hello")
(set-cdr! p "good")

如此Q以前定义的 p 又变成了 ("hello" . "good") q个样子了?/p>

列表(list)

列表是由多个相同或不同的数据q箋l成的数据类型,它是~程中最常用的复合数据类型之一Q很多过E操作都与它相关。下面是在Guile中列表的定义和相x作:

guile> (define la (list 1 2 3 4 ))
guile> la
(1 2 3 4)
guile> (length la) ; 取得列表的长?br>4
guile> (list-ref la 3) ; 取得列表W?的|?开始)
4
guile> (list-set! la 2 99) ; 讑֮列表W?的gؓ99
99
guile> la
(1 2 99 4)
guile> (define y (make-list 5 6)) ;创徏列表
guile> y
(6 6 6 6 6)

make-list用来创徏列表Q第一个参数是列表的长度,W二个参数是列表中添充的内容Q还可以实现多重列表Q即列表的元素也是列表,如:(list (list 1 2 3) (list 4 5 6))?/p>

列表与pair的关p?/h3>

回过头来Q我们再看看下面的定义:

guile> (define a (cons 1 (cons 2 (cons 3 '()))))
guile> a
(1 2 3)

׃可见Qa本来是我们上面定义的点对Q最后Ş成的却是列表。事实上列表是在点对的基上Ş成的一U特D格式?/p>

再看下面的代码:

guile> (define ls (list 1 2 3 4))
guile> ls
(1 2 3 4)
guile> (list? ls)
#t
guile> (pair? ls)
#t

由此可见Qlist是pair的子cdQlist一定是一个pairQ而pair不是list?/p>

guile> (car ls)
1
guile> (cdr ls)
(2 3 4)

其cdr又是一个列表,可见用于pair的操作过E大多可以用于list?/p>

guile> (cadr ls)   ; ?点对"对象的cdr的car
2
guile> (cddr ls) ; ?点对"对象的cdr的cdr
(3 4)
guile> (caddr ls) ; ?点对"对象的cdr的cdr的car
3
guile> (cdddr ls) ; ?点对"对象的cdr的cdr的cdr
(4)

上在的操作中用到的cadrQcdddr{过E是专门对PAIR型数据再复合形成的数据操作的q程Q最多可以支持在中间加四位a或dQ如cdddrQcaaddr{?/p>

下图表示了由pairs定义形成的列表:

http://www.oxsama.com/?k=data_image&p=static.d/1189119482-19692-0.rst.images/1.png

q个列表可以由pair定义为如下Ş式:

(define x (cons 'a (cons 'b (cons 'c (cons 'd '())))))

而列表的实际内容则ؓQ?a b c d)

由paircdq可以看出它可以L的表C树型结构,其是标准的二叉树?/p>

向量QvectorQ?/h3>

可以说是一个非常好用的cd Q是一U元素按整数来烦引的对象Q异源的数据l构Q在占用I间上比同样元素的列表要,在外观上Q?/p>

列表CZؓQ?(1 2 3 4) VECTOR表示为: #(1 2 3 4) 可以正常定义Q?define v (vector 3 4 5)) 也可以直接定义:(define v #(3 4 5))

vector是一U比较常用的复合cdQ它的元素烦引从0开始,至第 n-1 l束Q这一Ҏ点类似C语言中的数组?/p>

关于向量表(vectorQ的常用操作q程Q?/p>

guile> (define v (vector 1 2 3 4 5))
guile> v
#(1 2 3 4 5)
guile> (vector-ref v 0) ; 求第n个变量的?br>1
guile> (vector-length v) ; 求vector的长?br>5
guile> (vector-set! v 2 "abc") ; 讑֮vectorWn个元素的?br>guile> v
#(1 2 "abc" 4 5)
guile> (define x (make-vector 5 6)) ; 创徏向量?br>guile> x
#(6 6 6 6 6)

make-vector用来创徏一个向量表Q第一个参数是数量Q后一个参数是d的|q和列表中的make-list非常怼?/p>

我们可以看出Q在Scheme语言中,每种数据cd都有一些基本的和它相关的操作过E,如字W串Q列表等相关的操作,q些操作q程都很有规律,q程名的单词之间都用-号隔开Q很Ҏ理解。对于学qC++的朋友来_更类g某个对象的方法,只不q表现的形式不同了?/p>

3. cd的判断、比较、运、{换与Ҏ

cd判断

Scheme语言中所有判断都是用cd名加问号再加相应的常量或变量构成QŞ如:

(cd? 变量)

Scheme语言在类型定义中有比较严格的界定Q如在C语言{一些语a中数?来代曉K辑cd数据FalseQ在Scheme语言中是不允许的?/p>

以下为常见的cd判断和附加说明:

逻辑型:

(boolean? #t) => #t
(boolean? #f) => #t 因ؓ#t?f都是booleancdQ所以其gؓ#t
(boolean? 2) => #f 因ؓ2是数字类型,所以其gؓ #f

字符型:

(char? #\space) => #t
(char? #\newline) => #t 以上两个Ҏ字符Q空格和换行
(char? #\f) => #t 写字母 f
(char? #\;) => #t 分号 ;
(char? #\5) => #t 字符 5 Q以上这些都是正的Q所以返回值都?#t
(char? 5) => #f q是数字 5 Q不是字W类型,所以返?#f

数字型:

(integer? 1)            => #t
(integer? 2345) => #t
(integer? -90) => #t 以上三个数均为整?br>(integer? 8.9) => #f 8.9不整?br>(rational? 22/7) => #t
(rational? 2.3) => #t
(real? 1.2) => #t
(real? 3.14159) => #t
(real? -198.34) => #t 以上三个数均为实数型
(real? 23) => #t 因ؓ整型属于实型
(number? 5) => #t
(number? 2.345) => #t
(number? 22/7) => #t

其它型:

(null? '())             => #t  ; null意ؓI类型,它表CZؓ '() Q即括号里什么都没有的符?br>(null? 5)               => #f
(define x 123) 定义变量x其gؓ123
(symbol? x) => #f
(symbol? 'x) => #t ; 此时 'x 为符号xQƈ不表C变量x的?br>

在Scheme语言中如此众多的cd判断功能Q得Scheme语言有着非常好的自省功能。即在判断过E的参数是否附合q程的要求?/p>

比较q算

Scheme语言中可以用<Q?gt;Q?lt;=Q?gt;=Q? 来判断数字类型值或表达式的关系Q如判断变量x是否{于Ӟ它的形式是这LQ?= x 0) Q如x的gؓ0则表辑ּ的gؓ#tQ否则ؓ#f?/p>

q有下面的操作:

(eqv? 34 34)   =>  #t
(= 34 34) => #t

以上两个form功能相同Q说?eqv? 也可以用于数字的判断?/p>

在Scheme语言中有三种相等的定义,两个变量正好是同一个对象;两个对象h相同的|两个对象h相同的结构ƈ且结构中的内容相同。除了上面提到的W号判断q程和eqv?外,q有eq?和equal?也是判断是否相等的过E?/p>

eq?Qeqv?Qequal?

eq?Qeqv?和equal?是三个判断两个参数是否相{的q程Q其中eq?和eqv?的功能基本是相同的,只在不同的Scheme语言中表C一栗?/p>

eq?是判断两个参数是否指向同一个对象,如果是才q回#tQequal?则是判断两个对象是否h相同的结构ƈ且结构中的内Ҏ否相同,它用eq?来比较结构中成员的数量;equal?多用来判断点对,列表Q向量表Q字W串{复合结构数据类型?/p>

guile> (define v (vector 3 4 5))
guile> (define w #(3 4 5)) ; w和v都是vectorcdQ具有相同的?(3 4 5)
guile> (eq? v w)
#f ; 此时w和v是两个对?br>guile> (equal? v w)
#t ; W合equal?的判断要?br>

以上操作说明了eq? 和equal? 的不同之处,下面的操作更是证明了q一点:

guile> (define x (make-vector 5 6))
guile> x
#(6 6 6 6 6)
guile> (eq? x x) ; 是同一个对象,所以返?t
#t
guile> (define z (make-vector 5 6))
guile> z
#(6 6 6 6 6)
guile> (eq? x z) ; 不是同一个对?br>#f
guile> (equal? x z) ; l构相同Q内容相同,所以返?t
#t

术q算

Scheme语言中的q算W有Q? + , - , * , / ?expt (指数q算) 其中 - ?/ q可以用于单目运,如:

(- 4)  => -4
(/ 4) => 1/4

此外q有许多扩展的库提供了很多有用的q程Q?/p>

max 求最?(max 8 89 90 213)  => 213
min 求最?(min 3 4 5 6 7) => 3
abs 求绝对?(abs -7) ==> 7

除了maxQminQabs外,q有很多数学q算q程Q这要根据你用的Scheme语言的运行环境有养I不过它们大多是相同的。在R5RS中规定了很多q算q程Q在R5RS的参考资料中可以很容易找到?/p>

转换

Scheme语言中用W号l合"->"来标明类型间的{换(很象C语言中的指针Q的q程Q就象用问号来标明类型判断过E一栗下面是一些常见的cd转换q程Q?/p>

guile> (number->string 123)  ; 数字转换为字W串
"123"
guile> (string->number "456") ; 字符串{换ؓ数字
456
guile> (char->integer #\a) ;字符转换为整型数Q小写字母a的ASCII码gؓ96
97
guile> (char->integer #\A) ;大写字母A的gؓ65
65
guile> (integer->char 97) ;整型数{换ؓ字符
#\a
guile> (string->list "hello") ;字符串{换ؓ列表
(#\h #\e #\l #\l #\o)
guile> (list->string (make-list 4 #\a)) ; 列表转换为字W串
"aaaa"
guile> (string->symbol "good") ;字符串{换ؓW号cd
good
guile> (symbol->string 'better) ;W号cd转换为字W串
"better"

五.q程定义

q程QProcedureQ?/h2>

在Scheme语言中,q程相当于C语言中的函数Q不同的是Scheme语言q程是一U数据类型,q也是ؓ什么Scheme语言程序和数据作ؓ同一对象处理的原因。如果我们在Guile提示W下输入加号然后回RQ会出现下面的情况:

guile> +
#<primitive-procedure +>

q告诉我?+"是一个过E,而且是一个原始的q程Q即Scheme语言中最基础的过E,在GUILE中内部已l实现的q程Q这和类型判断一P? boolean?{,它们都是Scheme语言中最基本的定义。注意:不同的Scheme语言实现环境Q出现的提示信息可能不尽相同Q但意义是一L?/p>

define不仅可以定义变量Q还可以定义q程Q因在Scheme语言中过E(或函敎ͼ都是一U数据类型,所以都可以通过define来定义。不同的是标准的q程定义要用lambdaq一关键字来标识?/p>

Lambda关键?/h2>

Scheme语言中可以用lambda来定义过E,其格式如下: (define q程?( lambda (参数 ...) (操作q程 ...)))

我们可以自定义一个简单的q程Q如下:

::
(define add5 (lambda (x) (+ x 5)))

此过E需要一个参敎ͼ其功能ؓq回此参数加5 的|如:

(add5 11) => 16

下面是简单的求^方过Esquare的定义:

(define square (lambda (x)  (* x x)))

与lambda相同的另一U方?/h2>

在Scheme语言中,也可以不用lambdaQ而直接用define来定义过E,它的格式为: (define (q程?参数) (q程内容 …))

如下面操作:

(define (add6 x) (+ x 6))
add6
#<procedure: add6 (x)> 说明add6是一个过E,它有一个参数x
(add6 23) => 29

再看下面的操作:

guile> (define fun
(lambda(proc x y)
(proc x y)))
guile> fun
#<procedure fun (proc x y)>
guile> (fun * 5 6)
30
guile> (fun / 30 3)
10

更多的过E定?/h2>

上面定义的过Efun有三个参敎ͼ其中W一个参数proc也是一个操作过E(因ؓ在Scheme语言中过E也是一U数据,可以作ؓq程的参敎ͼQ另外两个参数是数|所以会出现上面的调用结果?/p>

guile> (define add
(lambda (x y)
(+ x y)))
guile> add
#<procedure add (x y)>
guile> (fun add 100 200)
300

l箋上面操作Q我们定义一个过EaddQ将add作ؓ参数传递给funq程Q得出和(fun + 100 200)相同的结果?/p>

guile> ((lambda (x) (+ x x)) 5)
10

上面?(lambda(x) (+ x x)) 事实上是单的q程定义Q在后面直接加上操作参数5Q得出结?0Q这样实C匿名q程Q直接用q程定义来操作参敎ͼ得出q算l果?/p>

通过上面的操作,怿你已初步了解了过E的用法。既然过E是一U数据类型,所以将q程作ؓq程的参数是完全可以的。以下过Eؓ判断参数是否E,l出一个参敎ͼ?procedure? 来判断参数是否ؓq程Q采用ifl构Q关于ifl构见下面的介绍Q:

guile> (define isp
(lambda (x)
(if (procedure? x) 'isaprocedure 'notaprocedure)))
guile> isp
#<procedure isp (x)>
guile> (isp 0)
notaprocedure
guile> (isp +)
isaprocedure

上面的过E就体现了Scheme语言的参数自省(辨别Q能力,'0'是数字型Q所以返回notaprocedureQ?+'是一个最基础的操作过E,所以返回isaprocedure?/p>

q程的嵌套定?/h2>

在Scheme语言中,q程定义也可以嵌套,一般情况下Q过E的内部q程定义只有在过E内部才有效Q相当C语言中的局部变量?/p>

如下面的代码的最l结果是50Q?/p>

(define fix
(lambda (x y z)
(define add
(lambda (a b) (+ a b)))
(- x (add y z))))
(display (fix 100 20 30))

此时q程add只在fixq程内部起做用,q事实上涉及了过E和变量的绑定,可以参考下面的关于q程l定QletQlet* 和letrecQ的介绍?/p>

q程是初学者难理解的一个关键,随着q程参数的增加和功能的增强,q程的内容变得越来越复杂Q小括号也会更多Q如果不写出清晰的代码的话,M码也会成Z个难题?/p>

熟悉?scheme 基本概念、数据类型和q程Q函敎ͼ后, 下一部分我们来学?scheme 的结构、递归调用和其他扩展功能?/p>

六.常用l构

序l构

也可以说成由多个forml成的formQ用begin来将多个form攑֜一对小括号内,最lŞ成一个form。格式ؓQ?begin form1 form2 …)

如用Scheme语言写成的经典的helloworldE序是如下样子的Q?/p>

(begin
(display "Hello world!") ; 输出"Hello world!"
(newline)) ; 换行

ifl构

Scheme语言的ifl构有两U格式,一U格式ؓQ?if 试 q程1 q程2)Q即试条g成立则执行过E?Q否则执行过E?。例如下面代码:

(if (= x 0)
(display "is zero")
(display "not zero"))

q有另一U格式:(if 试 q程) Q即试条g成立则执行过E。例如下面代码:

(if (< x 100) (display "lower than 100"))

Ҏcd判断来实现自省功能,下面代码判断l定的参数是否ؓ字符Ԍ

(define fun
(lambda ( x )
(if (string? x)
(display "is a string")
(display "not a string"))))

如执?(fun 123) 则返回gؓ"not a string"Q这L功能在C++或JAVA中实现的话可能会很费力气?/p>

condl构

Scheme语言中的condl构cM于C语言中的switchl构Qcond的格式ؓQ?/p>

(cond ((试) 操作) … (else 操作))

如下是在Guile中的操作Q?/p>

guile> (define w (lambda (x)
(cond ((< x 0) 'lower)
((> x 0) 'upper)
(else 'equal))))
guile> w
#<procedure w (x)>
guile> (w 9)
upper
guile> (w -8)
lower
guile> (w 0)
equal

上面E序代码中,我们定义了过EwQ它有一个参数xQ如果x的值大?Q则q回W号upperQ如x的值小?则返回符号lowerQ如x 的gؓ0则返回符号equal?/p>

下蝲已做成可执行脚本?例程?/p>

cond可以用if形式来写Q上面的q程可以如下定义Q?/p>

guile> (define ff
(lambda (x)
(if (< x 0) 'lower
(if (> x 0) 'upper 'zero))))
guile> ff
#<procedure ff (x)>
guile> (ff 9)
upper
guile> (ff -9)
lower
guile> (ff 0)
zero

q在功能上是和cond一LQ可以看出cond实际上是实现了if的一U多重嵌套?/p>

casel构

casel构和condl构有点cMQ它的格式ؓQ?/p>

(case (表达? ((? 操作)) ... (else 操作)))

casel构中的值可以是复合cd数据Q如列表Q向量表{,只要列表中含有表辑ּ的这个结果,则进行相应的操作Q如下面的代码:

(case (* 2 3)
((2 3 5 7) 'prime)
((1 4 6 8 9) 'composite))

上面的例子返回结果是compositeQ因为列?1 4 6 8 9)中含有表辑ּ(* 2 3)的结?Q下面是在Guile中定义的funcq程Q用Ccasel构Q?/p>

guile> (define func
(lambda (x y)
(case (* x y)
((0) 'zero)
(else 'nozero))))
guile> func
#<procedure func (x y)>
guile> (func 2 3)
nozero
guile> (func 2 0)
zero
guile> (func 0 9)
zero
guile> (func 2 9)
nozero

可以下蝲另一个脚本文?te.scmQ参考一下?/p>

andl构

andl构与逻辑与运操作类|and后可以有多个参数Q只有它后面的参数的表达式的值都?tӞ它的q回值才?tQ否则ؓ#f。看下面的操作:

guile> (and (boolean? #f) (< 8 12))
#t
guile> (and (boolean? 2) (< 8 12))
#f
guile> (and (boolean? 2) (> 8 12))
#f

如果表达式的值都不是boolean型的话,q回最后一个表辑ּ的|如下面的操作Q?/p>

guile> (and (list 1 2 3) (vector 'a 'b 'c))
#(a b c)
guile> (and 1 2 3 4 )
4
guile> (and 'e 'd 'c 'b 'a)
a

orl构

orl构与逻辑或运操作类|or后可以有多个参数Q只要其中有一个参数的表达式gؓ#tQ其l果׃ؓ#tQ只有全?f时其l果才ؓ#f。如下面的操作:

guile> (or #f #t)
#t
guile> (or #f #f)
#f
guile> (or (rational? 22/7) (< 8 12))
#t
guile> (rational? 22/7)
#t
guile> (real? 22/7)
#t
guile> (or (real? 4+5i) (integer? 3.22))
#f

我们q可以用and和orl构来实现较复杂的判断表辑ּQ如在C语言中的表达式:

((x > 100) && (y < 100)) ?((x > 100) || (y > 100))

在Scheme中可以表CZؓQ?/p>

guile> (define x 123)
guile> (define y 80)
guile> (and (> x 100) (< y 100))
#t
guile> (or (> x 100) (> y 100))
#t

Scheme语言中只有ifl构是系l原始提供的Q其它的condQcaseQandQorQ另外还有doQwhenQunless{都是可以用宏定义的方式来定义的Q这一点充分体CScheme的元语言Ҏ,关于doQwhen{结构的使用可以参考R5RS?/p>

七.递归调用

用递归实现阶乘

在Scheme语言中,递归是一个非帔R要的概念Q可以编写简单的代码很轻杄实现递归调用Q如下面的阶乘过E定义:

(define  factoral (lambda (x)
(if (<= x 1) 1
(* x (factoral (- x 1))))))

我们可以下面的调用(factoral 4)Q即4的阶乘的q算q程囄如下Q?/p> http://www.oxsama.com/?k=data_image&p=static.d/1189119482-19692-0.rst.images/2.jpg

以下为factoralq程在Guile中的q行情况Q?/p>

guile> (define factoral (lambda (x) (if (<= x 1) 1 (* x (factoral (- x 1))))))
guile> factoral
#<procedure factoral (x)>
guile> (factoral 4)
24

另一U递归方式

下面是一另一U递归方式的定义:

(define (factoral n)
(define (iter product counter)
(if (> counter n)
product
(iter (* counter product) (+ counter 1))))
(iter 1 1))
(display (factoral 4))

q个定义的功能和上面的完全相同,只是实现的方法不一样了Q我们在q程内部实现了一个过EiterQ它用counter参数来计敎ͼ调用时从1开始篏计,q样它的展开q程正好和我们上面的递归q程的从4?相反Q而是???/p>

循环的实?/h2>

在Scheme语言中没有@环结构,不过循环l构可以用递归来很L的实玎ͼ在Scheme语言中只有通过递归才能实现循环Q。对于用惯了C语言循环的朋友,在Scheme中可以用递归单实玎ͼ

guile> (define loop
(lambda(x y)
(if (<= x y)
(begin (display x) (display #\\space) (set! x (+ x 1))
(loop x y)))))
guile> loop
#<procedure loop (x y)>
guile> (loop 1 10)
1 2 3 4 5 6 7 8 9 10

q只是一U简单的循环定义Q过E有两个参数Q第一个参数是循环的初始|W二个参数是循环l止|每次增加1。相信读者朋友一定会写出更漂亮更实用的@环操作来的?/p>

八.变量和过E的l定

letQlet*Qletrec

在多数编E语a中都有关于变量的存在的时限问题,Scheme语言中用letQlet*和letrec来确定变量的存在的时限问题,卛_部变量和全局变量Q一般情况下Q全局变量都用define来定义,q放在过E代码的外部Q而局部变量则用let{绑定到q程内部使用?/p>

用let可以变量或q程l定在过E的内部Q即实现局部变量:

guile> let
#<primitive-macro! let>

从上面的操作可以看出let是一个原始的宏,即guile内部已经实现的宏定义?/p>

下面的代码显CZlet的用法(注意多了一层括PQ?/p>

guile> (let ((x 2) (y 5)) (* x y))
10

它的格式是:(let ((…)…) …)Q下面是E复杂的用法Q?/p>

guile> (let ((x 5))
(define foo (lambda (y) (bar x y)))
(define bar (lambda (a b) (+ (* a b) a)))
(foo (+ x 3)))
45

以上是Guile中的代码实现情况。它的实现过E大致是Q?foo 8) 展开后Ş?(bar 5 8)Q再展开后Ş?(+ (* 5 8) 5) Q最后其gؓ45?/p>

再看下面的操作:

guile> (let ((iszero?
(lambda(x)
(if (= x 0) #t #f))))
(iszero? 9))
#f
guile> (iszero? 0) ;此时会显C出错信?br>

let的绑定在q程内有效,q程外则无效Q这和上面提到的q程的嵌套定是一LQ上面的iszero?q程在操作过E内定义q用的Q操作结束后再另行引用则无效Q显CE未定义出错信息?/p>

下面操作演示了let*的用法:

guile> (let ((x 2) (y 5))
(let* ((x 6)(z (+ x y))) ;此时x的值已?Q所以z的值应?1Q如此最后的gؓ66
(* z x)))
66

q有letrecQ看下面的操作过E:

guile> (letrec ((even?
(lambda(x)
(if (= x 0) #t
(odd? (- x 1)))))
(odd?
(lambda(x)
(if (= x 0) #f
(even? (- x 1))))))
(even? 88))
#t

上面的操作过E中Q内部定义了两个判断q程even?和odd?Q这两个q程是互盔R归引用的,如果letrec换成let或let*都会不正常,因ؓletrec是将内部定义的过E或变量间进行相互引用的。看下面的操作:

guile> (letrec ((countdown
(lambda (i)
(if (= i 0) 'listoff
(begin (display i) (display ",")
(countdown (- i 1)))))))
(countdown 10))
10,9,8,7,6,5,4,3,2,1,listoff

letrec帮助局部过E实现递归的操作,q不仅在letrecl定的过E内Q而且q包括所有初始化的东西,q得在~写较复杂的q程中经常用到letrecQ也成了理解它的一个难炏V?/p>

apply

apply的功能是为数据赋予某一操作q程Q它的第一个参数必需是一个过E,随后的其它参数必需是列表,如:

guile> (apply + (list 2 3 4))
9
guile> (define sum
(lambda (x )
(apply + x))) ; 定义求和q程
guile> sum
#<procedure sum (x)>
guile> (define ls (list 2 3 4 5 6))
guile> ls
(2 3 4 5 6)
guile> (sum ls)
20
guile> (define avg
(lambda(x)
(/ (sum x) (length x)))) ; 定义求^均过E?br>guile> avg
#<procedure avg (x)>
guile> (avg ls)
4

以上定义了求和过Esum和求q_的过EavgQ其中求和的q程sum中用Capply来绑?+"q程操作到列表,l果q回列表中所有数的d?/p>

map

map的功能和apply有些怼Q它的第一个参C必需是一个过E,随后的参数必需是多个列表,q回的结果是此过E来操作列表后的|如下面的操作Q?/p>

guile> (map + (list 1 2 3) (list 4 5 6))
(5 7 9)
guile> (map car '((a . b)(c . d)(e . f)))
(a c e)

除了applyQmap以外QScheme语言中还有很多,诸如QevalQdelayQfor-eachQforceQcall-with- current- continuation{过E绑定的操作定义Q它们都无一例外的提供了相当灉|的数据处理能力,也就是另初学者望而生畏的法Q当你仔l的体会了运过 E中用到的简直妙不可a的算法后Q你׃发现Scheme语言设计者的思想是多么伟大?/p>

九.输入输出

Scheme语言中也提供了相应的输入输出功能Q是在C基础上的一U封装?/p>

端口

Scheme语言中输入输Z用到了端口的概念Q相当于C中的文g指针Q也是Linux中的讑֤文gQ请看下面的操作Q?/p>

guile> (current-input-port)
#<input: standard input /dev/pts/0> ;当前的输入端?br>guile> (current-output-port)
#<output: standard output /dev/pts/0> ;当前的输出端?br>

判断是否入输出端口,可以用下面两个过E:input-port? 和output-port? Q其中input-port?用来判断是否入端口,output-port?用来判断是否出端口?/p>

open-input-fileQopen-output-fileQclose-input-portQclose-output-portq四个过E用来打开和关闭输入输出文Ӟ其中打开文g的参数是文g名字W串Q关闭文件的参数是打开的端口?/p>

输入

打开一个输入文件后Q返回的是输入端口,可以用readq程来输入文件的内容Q?/p>

guile> (define port (open-input-file "readme"))
guile> port
#<input: readme 4>
guile> (read port)
GUILE语言

上面的操作打开了readme文gQƈd了它的第一行内宏V此外还可以直接用readq程来接攉盘输入,如下面的操作Q?/p>

guile> (read)  ; 执行后即{待键盘输入
12345
12345
guile> (define x (read)) ; {待键盘输入q赋值给x
12345
guile> x
12345

以上为用read来读取键入的数字Q还可以输入字符串等其它cd数据Q?/p>

guile> (define name (read))
tomson
guile> name
tomson
guile> (string? name)
#f
guile> (symbol? name)
#t

此时输入的tomson是一个符L型,因ؓ字符串是用引号引h的,所以出C面的情况。下面因为用引号了,所?string? str)q回gؓ#t ?/p>

guile> (define str (read))
"Johnson"
guile> str
"Johnson"
guile> (string? str)
#t

q可以用loadq程来直接调用Scheme语言源文件ƈ执行它,格式为:(load "filename")Q还有read-charq程来读单个字符{等?/p>

输出

常用的输E是displayQ还有writeQ它的格式是Q?write 对象 端口)Q这里的对象是指字符串等帔R或变量,端口是指输出端口或打开的文件。下面的操作q程演示了向输出文gtemp中写入字W串"helloworld"Qƈ分行的实现?/p>

[root@toymouse test]# guile
guile> (define port1 (open-output-file "temp")) ; 打开文g端口赋于port1
guile> port1
#<output: temp 3>
guile> (output-port? port1)
#t ; 此时证明port1出端?br>guile> (write "hello\\nworld" port1)
guile> (close-output-port port1)
guile> (exit) ; 写入数据q关闭退?br>[root@toymouse test]# more temp 昄文g的内容,辑ֈ试目的
"hello
world"

在输入输出操作方面,q有很多相关操作Q读者可以参考R5RS的文档?/p>

十.语法扩展

Scheme语言可以自己定义象condQlet{功能一L宏关键字。标准的Scheme语言定义中用define-syntax和syntax-rules来定义,它的格式如下Q?/p>

(define-syntax 宏名
(syntax-rules()
((模板) 操作))
. . . ))

下面定义的宏start的功能和begin相同Q可以用它来开始多个块的组合:

(define-syntax start
(syntax-rules ()
((start exp1)
exp1)
((start exp1 exp2 ...)
(let ((temp exp1)) (start exp2 ...))) ))

q是一个比较简单的宏定义,但对理解宏定义来说是比较重要的,理解了他你才会进一步应用宏定义。在规则 ((start exp1) exp1) 中,(start exp1) 是一个参数时的模板,exp1是如何处理,也就是原h出,不做处理。这?(start form1) ? (form1) 的功能就相同了?/p>

在规?((start exp1 exp2 ...) (let ((temp exp1)) (start exp2 ...))) 中,(start exp1 exp2 …) 是多个参数时的模板,首先用let来绑定局部变量temp为exp1Q然后用递归实现处理多个参数Q注意这里说的是宏定义中的递归Qƈ不是q程调用中的? 归。另外在宏定义中可以用省略号Q三个点Q来代表多个参数?/p>

在Scheme的规范当中,表辑ּ分ؓ原始表达式和有源表达式,Scheme语言的标准定义中只有原始的if分支l构Q其它均为有源型Q即是用后来的宏定义成的Q由此可见宏定义的重要性。附上面的定义在GUILE中实现的 代码?/p>

十一. 其它功能

1. 模块扩展

在R5RS 中ƈ未对如何~写模块q行说明Q在诸多的Scheme语言的实现当中,几乎无一例外的实C模块的加载功能。所谓模块,实际是一些变量、宏定义和已命名 的过E的集合Q多数情况下它都l定在一个Scheme语言的符号下Q也是名称Q。在Guile中提供了基础的ice-9模块Q其中包括POSIXpȝ? 用和|络操作、正则表辑ּ、线E支持等{众多功能,此外q有著名的SFRI模块。引用模块用use-modulesq程Q它后面的参数指定了模块名和我们 要调用的功能名,如:(use-modules (ice-9 popen))Q如此后Q就可以应用popenq一pȝ调用了。如果你惌定义自己的模块,最好看看ice-9目录中的那些tcm文gQ它们是最原始的定 义?/p>

另外Guile在面向对象编E方面,开发了GOOPSQGuile Object-Oriented Programming SystemQ,对于喜欢OO朋友可以研究一下它Q从中可能会有新的发现?/p>

2. 如何输出漂亮的代?/h2>

如何~写输出漂亮的Scheme语言代码应该是初学者的W一个问题,q在Guile中可以用ice-9扩展包中提供的pretty-printq程来实玎ͼ看下面的操作Q?/p>

guile> (use-modules (ice-9 pretty-print))    ; 引用漂亮输出模块
guile> (pretty-print '(define fix (lambda (n)
(cond ((= n 0) 'iszero)
((< n 0) 'lower)
(else 'upper))))) ; 此处是我们输入的不规则代?br>(define fix
(lambda (n)
(cond ((= n 0) 'iszero)
((< n 0) 'lower)
(else 'upper)))) ; 输出的规则代?br>

3. 命o行参数的实现

在把Scheme用做shell语言Ӟl常用到命o行参数的处理Q下面是关于命o行参数的一U处理方法:

#! /usr/local/bin/guile -s
!#
(define cmm (command-line))
(display "应用E序名称Q?)
(display (car cmm))
(newline)
(define args (cdr cmm))
(define long (length args))
(define loop (lambda (count len obj)
(if (<= count len)
(begin
(display "参数 ")
(display count)
(display " 是:")
(display (list-ref obj (- count 1)))
(newline)
(set! count (+ count 1))
(loop count len obj)))))
(loop 1 long args)

下面是运行后的输出结果:

[root@toymouse doc]# ./tz.scm abc 123 ghi
应用E序名称Q?/tz.scm
参数 1 是:abc
参数 2 是:123
参数 3 是:ghi

其中最主要的是用到了command-lineq程Q它的返回结果是命o参数的列表,列表的第一个成员是E序名称Q其后ؓ我们要的参数Q定义loop递归调用形成d数的循环Q显C出参数|辑ֈ我们要的l果?/p>

4. Ҏ之处

一些精的自己计算自己的符?/p>

数字      Numbers         2 ==> 2
字符? Strings "hello" ==> "hello"
字符 Charactors #\\g ==> #\\g
辑? Booleans #t ==> #t
量表 Vectors #(a 2 5/2) ==> #(a 2 5/2)

通过变量计算来求值的W号

如:

x ==> 9
-list ==> ("tom" "bob" "jim")
factoral ==> #<procedure: factoral>
==> #<primitive: +>

define Ҏ的form

(define x 9) Qdefine不是一个过E, 它是一个不用求所有参数值的Ҏ的formQ它的操作步骤是Q初始化I间Q绑定符号x到此I间Q然后初始此变量?/p>

必须C的东?/h2>

下面的这些定义、过E和宏等是必记住的Q?/p>

defineQlambdaQletQletsQletrecQquoteQset!QifQcaseQcondQbeginQandQor{等Q当然还有其它宏Q必需学习Q还有一些未介绍Q可参考有兌料?/p>

走进Scheme语言的世界,你就发现法和数据结构的妙用随处可见Q可以充分的验你对算法和数据l构的理解。Scheme语言虽然是古老的函数型语a的l,但是它的里面有很多是在其它语a中学不到的东西,我想q也是ؓ什么用它作机语言教学的首选的原因吧?/p>

参考资?/h2>

关于作?/h2>

宋国伟( mailto:gwsong52@sohu.com Q,目前?吉林省d惠市信息中心 从事|络l护工作Q著?《GTK+2.0~程范例?/a> 一书,热衷于Linuxpȝ上的~程及相关的研究?/p>

cuigang 2007-12-23 20:43 发表评论
]]> þþþùƷ| ޾Ʒ׽þþþþ| Ʒþøһ| avھƷþþþӰԺ| ݺݺɫۺϾþð| Ʒ99þþþþwww| þþþavӰ| һɫþ88ۺպƷ | þݺҹҹվ | þþۺ㽶ۺ| þAVĻ| þþƷĻ鶹 | þþƷһ| 99þֻоƷ| ĻȾþþþþþ| Ⱦþۺ| 츾þþ| þþƷ޾Ʒŷ| þþþùƷŮӰԺ| ҹƷþþþþ˳| ھƷþþžŹƷ| ɫۺϾþ | ۺһ˾þþƷ | þþ޾Ʒ| 777þµַ| ޹Ʒþһ | þþùƵ| ܻƺ۵վþmimiɫ| AVþþþò | 91þþƷһëƬ| ˾þô߽| Ҫþðѹۿ| þˬˬƬAV| 99þۺϺݺۺϾþ| þ| þó˾ƷƵ| ˾þô߽槼| þþƷþ˼˼| ѾþҹƷ| ƷþòҰ| þþþþþۺ|