Scheme语言入门

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

Scheme语言入门

最早听说 LISP,是 Stallman 的 GNU Emacs 中将 LISP 作为嵌入语言,定制和增强 Emacs。GNU Emacs 是一个文本编辑器,文本就是一种符号,而 Lisp 正好就是针对符号计算发明的,因此在GNU Emacs 中使用 Lisp 是顺理成章的事情。

Lisp 语言的历史已经很久了,几乎与 Fortran 一样长。二十世纪五十年代,计算机科学家先是发明了针对数字计算的 Fortran 语言,后来针对符号计算,由MIT 的John McCarthy于1960年开发出了Lisp(List processing)语言。该语言原来是为表处理而设计的编程语言,后来广泛用于处理人工智能问题。Lisp 程序中充满了一对对嵌套的小括号,这些嵌套的符号表达式体现着递归。递归是数学上的基本概念之一,从递归理论出发,一切可以计算的函数最终都可以划归为几种基本的递归函数的种种组合。

1994年时众多 Lisp 版本又得到了相当的统一,统一之后的版本称为Common LISP。Common Lisp 含有非常丰富的库,仅仅语言的规范就长达千页以上,包括面向对象的 CLOS。

Scheme 语言是 Lisp 的一个现代变种、方言,诞生于1975年,由 MIT 的 Gerald J. Sussman and Guy L. Steele Jr. 完成。Scheme语言的规范很短,总共只有50页,甚至连Common Lisp 规范的索引的长度都不到,但是却被称为是现代编程语言王国的皇后。它与以前和以后的 Lisp 实现版本都存在一些差异,但是却易学易用。

DSSSL需要完成的工作是解析文档,它的设计就采用了Scheme语言。本书时介绍DocBook的专著,因此并不打算写一个Scheme大全,只是想通过蜻蜓点水的介绍使读者认识Scheme,能够达到看懂和简单的修改DSSSL。

Scheme特点

Scheme语言具有它独特的魅力,看看Scheme的语法特点:

  • 括号嵌套

    Lisp 程序中充满了一对对嵌套的小括号,这些嵌套的符号体现了最基本的数学思想——递归。

  • 语法简洁

    Scheme语言的规范很短,总共只有50页。

  • 函数编程语言

    一个函数(Function)是这个编程语言中所谓的第一等的公民。也就是说函式可以像一个 int 或者 float 一样被很方便的传递来传递去。这也就是所谓"Functional 编程语言"中,Functional 一词的由来。

  • 自动内存管理

    自动内存管理可不是JAVA的专利呦。

  • 可移植性好

    Scheme开发的程序有很好的可移植性,这是由于Scheme是一种解释语言,在不同的平台都可以有相应的解释器。

  • 适合于作为脚本语言和嵌入语言

    语法简洁,这使得Scheme的实现可以非常的经济,一个Scheme解释器可以非常的小巧。Scheme可以作为脚本语言而内嵌于一些工具之中,如:GNU Emacs。

其他特点还有,关键字对大小写不敏感。

数据结构

  • 数字

    下面都是合法的数字表示方法:47,1/3,2.3,4.3e14,1+3i。

  • 字符

    字符前面需要用#\做前缀。如下面都是合法字符:

    #\a #\A #\b #\B #\space #\newline

  • 字符串

    由双引号括起来的字符组成字符串。如:"A little string"

  • 布尔值

    布尔值True和False分别用 #t 和 #f 表示。

  • 列表

    用圆括号括起来的,可以包含任何数据类型的称为列表。如: (a little (list of) (lists))

  • 数组(vector)

    用#为前缀,如: #(1 2 "string" #\x 5)

  • 函数(或称为过程)

    把函数作为一种数据类型,是Scheme语言的特色。

  • 符号

    符号除了不能够以数字开头的任何字符可组成符号。如:Symbols: this-is-a-symbol foo a32 c$23*4&7+3-is-a-symbol-too!

表达式和函数

注释

分号开始一段注释。如:

(+ 3 1) ;return 4

 

常量表达式

  1. 常量表达式

    常量表达式返回本身的值。如:

    3.14 ; 返回 3.14 #t ; 返回布尔值 #t #\c ; 返回字符 #\c "Hi!" ; 返回字符串 "Hi!"
  2. 引用(Quotation)

    语法:(quote obj)  或者简写为 'obj

    (+ 2 3)   ; 返回 5 '(+ 2 3)  ; 返回列表 (+ 2 3) (quote (+ 2 3)) ; 返回列表 (+ 2 3)

表达式记法

Scheme的表达式的写法有些特别,表达式用括号括起来。括号里面的第一个出线的是函数名或者操作符,其它是参数。Scheme的这种表达式写法可以叫做前置式。下面是一些Scheme的表达式的例子以及其对应的C语言的写法。

  Scheme                               C ------------------------------------------------------------------ (+ 2 3 4)                       (2 + 3 + 4)  (< low x high)                  ((low < x) && (x < high))  (+ (* 2 3)                      (* 4 5)) ((2 * 3) + (4 * 5))  (f x y)                         f(x, y)  (define (sq x) (* x x))         int sq(int x) { return (x * x) }

 

赋值和函数定义

  1. let 表达式和赋值

    语法:(let ((var val) ...) exp1 exp2 ...)

    说明:let 表达式的赋值只在表达式内部有效。

    示例:

    (let ((x 2) (y 3)) (+ x y))

    ; 先赋值: x=2, y=3,再计算x+y的值,结果为5。注意 (x 2) 和 (y 3) 外还有一层括号。

    更多的示例:

    (let ((f +))   (f 2 3))  ; return 5  (let ((f +) (x 2))   (f x 3))  ; return 5  (let ((f +) (x 2) (y 3))   (f x y))  ; return 5
  2. 用define 和 set! 赋值

    语法:(define var exp)  , (set! var exp)

    说明:define和 set! 表达式的赋值在全局有效。define 和 set! 的区别是define既能赋值又能定义变量,而set!只能对已经定义的变量赋值。

    示例:

    (define a 1)   a ; return 1 (set! a 2) a ; return 2 (let ((a 3)) a)  ; return 3 a ; return 2 (let ((a 3)) (set! a 4) a) ; return 4 a ; return 2 (let ((a 3)) (define a 5) a) ; return 5 a ; return 2 (set! b 1) ; 错误,b尚未定义
  3. lambda 表达式和函数定义

    语法:(lambda (var ...) exp1 exp2 ...)

    说明:lambda 表达式用于定义函数。var ... 是参数,exp1 exp2 ...是函数的执行 部分。通常需要结合局部定义 let 或者全局定义表达式 define,再进行函数调用。

    示例:

    ((lambda (x) (+ x x)) (* 3 4))  ; return 24

    说明:先用lambda定义了函数,参数是x,函数返回x+x。同时该语句也完成了函数调用,实参是 12 (等于3*4),因此返回值是 24 (等于12+12)。

  4. 在let表达式中定义函数。

    Scheme语言中,函数作为一种数据类型,通过赋值语句,将lambda表达式赋值给相应的函数。

    示例:

    (let ((double (lambda (x) (+ x x))))   (list (double (* 3 4))         (double (/ 99 11))         (double (- 2 7))))     ; return (24 18 -10)

    说明:let表达式将lambda定义的函数赋值给double,参数是x,返回 x+x。接下来分别三次调用 double 函数,并将结果以列表形式返回。list 表达式负责生成列表。

  5. 用define全局定义表达式来定义函数。

    用 let 定义的函数只能在 let 表达式中有效,如果想定义在整个程序中有效的函数定义,需要用到全局定义表达式——define。

    示例:

    (define double (lambda (x) (+ x x))) (double 12)            ; return 24 (double (* 3 4))       ; return 24

    说明:define表达式定义了全局有效的函数 double。两次调用double的返回值都是 24。

  6. 定义函数的简写

    用 define 定义的函数的语法可以简化,即将 lambda 去掉。即将语法

    (define var0   (lambda (var1 ... varn)     e1 e2 ...))

    简写为:

    (define (var0 var1 ... varn)   e1 e2 ...)

    示例:

    (define (double x) (+ x x)) (double 12)            ; return 24 (double (* 3 4))       ; return 24

    说明:本例是前一个例子的简化版本。更简介,明了。

顺序计算表达式

语法:(begin exp1 exp2 ...)

说明:顺序执行表达式 exp1, exp2, ...,返回最后一个表达式的结果

示例:

(define x 3) (begin   (set! x (+ x 1))   (+ x x))             ; 返回结果 8

 

说明:begin 表达式,依次先用set!表达式为x赋值为4,在运算x+x,返回结果8。

条件表达式

  1. 关系运算符

    (< -1 0)   #t (> -1 0)   #f  (eqv? 'a 'a)  #t
  2. 逻辑运算

    (not #t)   #f (not #f)  #t  (not 1)   #f (not '(a b c))   #f  (or)   #f (or #f)   #f (or #f #t)   #t (or #f 'a #f)   a  (and)   #t (and #f)   #f (and #f #t)   #f (and #f 'a #f)   #f (and 'a #t 'b) 'b
  3. if 表达式

    语法:(if test consequent alternative)

    说明:如果test表达式为真,返回 consequent,否则返回 alternative。

    示例:

    (define (abs n)     (if (< n 0)         (- 0 n)         n))

    说明:函数abs功能为取绝对值。

  4. cond 表达式

    语法:(cond (test exp) ... (else exp))

    说明:多路分支判断表达式,类似于C语言的 "if ... else if ... else"。

    示例:

    (define abs   (lambda (n)     (cond       ((= n 0) 0)       ((< n 0) (- 0 n))       (else n))))

    说明:用cond表达式重新实现取绝对值函数 abs。

  5. case 表达式

    语法:(case exp0 clause1 clause2 ... )

    clause 的语法结构为:((key1 ...) exp1 ...) 最后一个表达式的结构可以为:(else exp1 exp2 ...)

    说明:类似于C语言的 "switch ... case..." 语句。

    示例:

    (let ((x 4) (y 5))   (case (+ x y)     ((1 3 5 7 9) 'odd)     ((0 2 4 6 8) 'even)     (else 'out-of-range))) ; 返回 odd

    说明:case 表达式先计算 x+y 的值为9,接下来在key中进行匹配,并返回对应的表达式的值 'odd。

循环

  1. do 表达式

    语法:(do ((var1 val1 update1) ...) (test res ...) exp ...)

    说明:类似于C语言的for循环。先将val1赋值给var1,...,之后循环开始,在每次循环的开始,先执行表达式 test,如果返回布尔值真,则循环终止,并返回结果 res,如果表达式 test返回布尔值#f,则运行表达式 exp...,之后依次用 update1 ... 的值来为变量 var1 ... 重新赋值。

    示例1:计算阶乘 n! = n*(n-1)!

    (define factorial   (lambda (n)     (do ((i n (- i 1)) (a 1 (* a i)))         ((zero? i) a))))  (factorial 10)  ; 返回 3628800

    说明:其对应的C语言实现如下

    long factorial(int n) { int  i=n; long a=1; for (i=n;; i--) { if (i == 0) return a; a *= i; } }

    示例2:计算fibonacci数列:f(n+1)=f(n)+f(n-1) , n>0, f(1)=1, f(0)=0

    (define fibonacci   (lambda (n)     (if (= n 0)         0         (do ((i n (- i 1)) (a1 1 (+ a1 a2)) (a2 0 a1))             ((= i 1) a1)))))  (fibonacci 6)  ; 返回 8

    说明:其对应的C语言实现如下

    long fibonacci(int n) { long f=1; int i = n; int a1= 1; int a2= 0; if (n == 0) return 0; while(1) { if (i == 1) return a1; i--; a1=a1+a2; a2=a1; } }
  2. map 表达式

    语法:(map procedure list1 list2 ...)

    说明:列表 list1 list2 ... 必须具有同样的长度;过程 procedure 接受的参数个数同列表的个数,各个列表中对应的变量分别作为过程 procedure 的参数被执行, 将每次的运算结果以列表形式返回。

    (map abs '(1 -2 3 -4 5 -6))  ; 返回 (1 2 3 4 5 6),abs接受一个参数 (map (lambda (x y) (* x y))      '(1 2 3 4)      '(8 7 6 5)) 返回(8 14 18 20) ,lambda (x y) 接收两个参数
  3. for-each 表达式

    语法:(for-each procedure list1 list2 ...)

    说明:同 map表达式, 但是不返回结果列表。

     

转载于:https://my.oschina.net/zhoukuo/blog/349453

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/401206.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何将docker 镜像上传到docker hub仓库

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 如何将docker 镜像上传到docker hub仓库 目录* 如何将docker 镜像上传到docker hub仓库 背景 1.注册docker hub账号 2.…

ThinkPHP框架 _ 学习3

【路由解析】 通过url地址get参数找到指定的控制器&#xff0c;并进行对应方法调用请求 http://网址/index.php?m模块名称&c控制器&a方法 以上url地址信息代码不够优雅、不安全。 tp框架url地址可以由以下四种 http://网址/index.php?mXX&cXX&aXX 基本get模…

The slave I/O thread stops(equal MySQL server ids)

在学习replication时遇到了如下问题&#xff1a;显然看到Slave_IO_Running 为NO 表示有问题&#xff1b;到日志里查看&#xff0c;错误如下&#xff1a;position 98100121 17:09:03 [ERROR] The slave I/O thread stops because master and slave have equal MySQL server ids;…

pytest配置文件pytest.ini

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 说明&#xff1a; pytest.ini是pytest的全局配置文件&#xff0c;一般放在项目的根目录下是一个固定的文件-pytest.ini可以…

基于积分墙盈利模式的APP架构思考

基于积分墙盈利模式的APP架构思考from: http://kuailiyu.cyzone.cn/article/4156.html个人感言&#xff1a;一款小游戏好不容易辛辛苦苦开发出来&#xff0c;但是在后期如何不注重推荐&#xff0c;其下场可想而知。而个人游戏开发者的产品很难实现应用内付费集成&#xff0c;技…

【死磕NIO】— 探索 SocketChannel 的核心原理

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 大家好&#xff0c;我是大明哥&#xff0c;一个专注于【死磕 Java】系列创作的程序员。 【死磕 Java 】系列为作者「chenssy…

session的存储方式

1、保存在IIS进程中 2、保存在StateServer上 3、保存在SQL Server数据库中 转载于:https://www.cnblogs.com/dashi/archive/2012/10/10/4034799.html

PixiJS - 基于 WebGL 的超快 HTML5 2D 渲染引擎

Pixi.js 是一个开源的HTML5 2D 渲染引擎&#xff0c;使用 WebGL 实现&#xff0c;不支持的浏览器会自动降低到 Canvas 实现。PixiJS 的目标是提供一个快速且轻量级的2D库&#xff0c;并能兼容所有设备。此外&#xff0c;让开发者无需了解WebGL&#xff0c;就可以感受到硬件加速…

腾讯的老照片修复算法,我把它搬到网上,随便玩

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 大家好&#xff0c;之前向大家介绍并跑通了腾讯开源的老照片修复算法&#xff08;AI 黑科技&#xff0c;老照片修复&#xf…

java的事务类型及定义

转载:什么是事务:首先,说说什么事务。我认为事务&#xff0c;就是一组操作数据库的动作集合。事务是现代数据库理论中的核心概念之一。如果一组处理步骤或者全部发生或者一步也不执行&#xff0c;我们称该组处理步骤为一个事务。当所有的步骤像一个操作一样被完整地执行&#x…

驱动开发 环境搭建(VS2008+WDK+DDKWzard)

这篇文章比较适合初学驱动&#xff0c;搭建一个自动化的环境对于开发来说是事半功倍啊&#xff1b; 开发驱动&#xff0c;首先就是搭建开发的环境。既然是开发windows下的驱动程序&#xff0c;那MS的开发工具是一定要的。现在vs都到2010了&#xff0c;所以&#xff0c;也不能总…

戏说领域驱动设计(十八)——内验

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475   验证在我们现实的生活中非常常见&#xff0c;比如您找工作得先整个面试验证你的能力是否靠谱&#xff1b;找对象得先验证…

Annotation版本的HelloWorld

hiberante 的 annotation历史&#xff1a; 在hibernate3以后&#xff0c;开始支持Annotation; 先有hiberante再有JPA&#xff0c;有了JPA标准之后&#xff0c;hibernate写了Annotation来支持JPA&#xff1b;所以 hibernate的annotation是JPA标准之下的&#xff0c;一般都直接用…

如何理解JavaScript中给变量赋值,是引用还是复制

一、JavaScript中值的类型 JavaScript中的值分为2大类&#xff1a;基本类型和引用类型。每种类型下面又分为5种类型。 基本类型&#xff1a; 数字类型&#xff1a;Number&#xff1b;字符串类型&#xff1a;String&#xff1b;布尔类型&#xff1a;Boolean(true和false)&#x…

CommonCollection1反序列化链学习

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 CommonsCollection1 1、前置知识 1.1、反射基础知识 1.1.1、 对象与类的基础知识 类&#xff08;class&#xff09;&am…

性能测试的目的与类型

1.性能测试的目的 (1)评估系统的能力&#xff1a;测试中得到的负荷和响应时间数据可以被用于验证所计划的模型的能力&#xff0c;并帮助作出决策&#xff1b;(2)寻找系统瓶颈&#xff0c;进行系统调优&#xff1b;(4)检测软件中的问题&#xff1b;(5)验证稳定性、可靠性&#x…

[转]VS2010+MFC解析Excel文件中数据

本文转自&#xff1a;http://www.vcfans.com/2010/08/vs2010-mfc-excel-file-in-the-data-analysis.html 前两天折腾一个小功能&#xff0c;需求是解析Excel中的数据出来。网上一般使用的方案&#xff1a;1. ODBC当数据库来操作。2. 使用第三方的类库3. 使用COM调用Excel.exe中…

MySQL索引机制(详细+原理+解析)

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 MySQL索引机制 永远年轻&#xff0c;永远热泪盈眶 一.索引的类型与常见的操作 前缀索引 MySQL 前缀索引能有效减小索引文…

War-Driving(战争驾驶***)

War-Driving总结性的文章 以后应该不会在到这方面过多的下功夫了。点我下载转载于:https://blog.51cto.com/0x007/1586376

OpenCV笔记(十五)——使用Laplace算子进行图像的边缘检测

在笔记十四中&#xff0c;我们使用了Sobel算子对图像进行边缘检测&#xff0c;理论依据是像素变化最快的地方最有可能是边缘处&#xff0c;所以使用sobel算子对图像做微分&#xff0c;得到的结果图像当中灰度较大的区域&#xff0c;即为边缘处。 在这里&#xff0c;我们使用Lap…