scheme_scheme 云闪付url - CSDN
精华内容
参与话题
  • scheme语言中文教程

    2020-07-28 23:32:45
    该中文教程详细介绍了scheme语言的语法,规则,是初学者的入门好教材
  • Scheme语言入门

    千次阅读 2019-05-17 10:42:28
    4.6.1.Scheme语言入门 最早听说 LISP,是 Stallman 的 GNU Emacs 中将 LISP 作为嵌入语言,定制和增强 Emacs。GNU Emacs 是一个文本编辑器,文本就是一种符号,而 Lisp 正好就是针对符号计算发明的,因此在GNU ...

    4.6.1. 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。

    4.6.1.1. Scheme特点

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

    • 括号嵌套

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

    • 语法简洁

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

    • 函数编程语言

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

    • 自动内存管理

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

    • 可移植性好

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

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

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

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

    4.6.1.2. 数据结构

    • 数字

      下面都是合法的数字表示方法: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!

    4.6.1.3. 表达式和函数

    4.6.1.3.1. 注释

    分号开始一段注释。如:

    (+ 3 1) ;return 4
    

    4.6.1.3.2. 常量表达式

    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)
      

    4.6.1.3.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) } 
    
    

    4.6.1.3.4. 赋值和函数定义

    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
      

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

    4.6.1.3.5. 顺序计算表达式

    语法:(begin exp1 exp2 ...)

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

    示例:

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

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

    4.6.1.3.6. 条件表达式

    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。

    4.6.1.3.7. 循环

    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表达式, 但是不返回结果列表。

     

     

    原文1:http://www.worldhello.net/doc/docbook_howto/ar01s04s06.html

    原文2:https://my.oschina.net/zhoukuo/blog/349453

    展开全文
  • Scheme协议详细介绍

    千次阅读 2018-10-17 18:33:59
    1.URL Scheme使用场景介绍 2.URL Scheme基础介绍 2.1 什么是URL Scheme? 2.2 URL Scheme协议格式解释 2.3 Scheme链接格式样式 3.URL Scheme如何使用 3.1 设置Scheme 3.2 获取Scheme跳转的参数,并添加跳转...

    目录介绍

    • 1.URL Scheme使用场景介绍
    • 2.URL Scheme基础介绍
      • 2.1 什么是URL Scheme?
      • 2.2 URL Scheme协议格式解释
      • 2.3 Scheme链接格式样式
    • 3.URL Scheme如何使用
      • 3.1 设置Scheme
      • 3.2 获取Scheme跳转的参数,并添加跳转方式
      • 3.3 调用方式
      • 3.4 如何判断一个Scheme是否有效
      • 3.5 Scheme在短信息中注意要点

    好消息

    • 博客笔记大汇总【16年3月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计47篇[近20万字],转载请注明出处,谢谢!
    • 链接地址:https://github.com/yangchong211/YCBlogs
    • 如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!

    关于Scheme应用案例

    关于链接

    1.URL Scheme使用场景介绍

    • URL Scheme使用场景,目前1,2,5使用场景很广,有没有一种熟悉的感觉?
      • 1.通过小程序,利用Scheme协议打开原生app
      • 2.H5页面点击锚点,根据锚点具体跳转路径APP端跳转具体的页面
      • 3.APP端收到服务器端下发的PUSH通知栏消息,根据消息的点击跳转路径跳转相关页面
      • 4.APP根据URL跳转到另外一个APP指定页面
      • 5.通过短信息中的url打开原生app

    2.URL Scheme基础介绍

    2.1 什么是URL Scheme?

    • android中的scheme是一种页面内跳转协议,是一种非常好的实现机制,通过定义自己的scheme协议,可以非常方便跳转app中的各个页面

    2.2 URL Scheme协议格式

    String urlStr="http://www.ycbjie.cn:80/yc?id=hello&name=cg";
    //url =            protocol + authority(host + port) + path + query
    //协议protocol=    http
    //域名authority=   www.ycbjie.cn:80
    //页面path=          /yc
    //参数query=       id=hello&name=cg
    //authority =      host + port
    //主机host=        www.ycbjie.cn
    //端口port=        80
    

    2.3 Scheme链接格式样式

    • 样式:[scheme]?/[host]/[path]?[query]

    3.URL Scheme如何使用

    3.1 设置Scheme

    • 在AndroidManifest.xml中对标签增加设置Scheme
    <activity
        android:name=".ui.main.ui.activity.SchemeFirstActivity"
        android:screenOrientation="portrait">
        <!--Android 接收外部跳转过滤器-->
        <!--要想在别的App上能成功调起App,必须添加intent过滤器-->
        <intent-filter>
            <!-- 协议部分配置 ,注意需要跟web配置相同-->
            <!--协议部分,随便设置 yc://ycbjie:8888/from?type=yangchong  -->
            <data android:scheme="yc"
                android:host="ycbjie"
                android:path="/from"
                android:port="8888"/>
    
    
            <!--下面这几行也必须得设置-->
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <action android:name="android.intent.action.VIEW" />
        </intent-filter>
    </activity>
    

    3.2 获取Scheme跳转的参数,并添加跳转方式

    public class SchemeFirstActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Uri uri = getIntent().getData();
            if (uri != null) {
                //获取指定参数值
                String type = uri.getQueryParameter("type");
                Log.e( "UrlUtils","main: " + type);
    
                if(type.equals("yangchong")){
                    ActivityUtils.startActivity(GuideActivity.class);
                }else if(type.equals("main")){
                    ActivityUtils.startActivity(MainActivity.class);
                }
            }
            finish();
        }
    }
    

    3.3 调用方式

    • 3.3.1 原生调用
    Intent intent = new Intent(Intent.ACTION_VIEW,Uri.parse("yc://ycbjie:8888/from?type=yangchong"));
    startActivity(intent);
    
    • 3.3.2 网页调用
    <a href="yc://ycbjie:8888/from?type=yangchong">打开叮咚app</a>
    
    • 3.3.3 短信息中调用

    3.4 如何判断一个Scheme是否有效

    PackageManager packageManager = getPackageManager();
    Intent intent = new Intent(Intent.ACTION_VIEW,
            Uri.parse("yc://ycbjie:8888/from?type=yangchong"));
    List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
    boolean isValid = !activities.isEmpty();
    if (isValid) {
        startActivity(intent);
    }
    

    3.5 Scheme在短信息中注意要点

    • 设置android:scheme="http"或者android:scheme="https"后,点击短信息或者h5页面,发现没有跳到指定的页面,反而打开的是网页链接。

    关于我的博客

    展开全文
  • Scheme 语言概要(上)

    万次阅读 2015-08-27 18:06:45
    作为Lisp 变体,Scheme 是一门非常简洁的计算语言,使用它的编程人员可以摆脱语言本身的复杂性,把注意力集中到更重要的问题上,从而使语言真正成为解决问题的工具。本文分为上、 下两部分来介绍 scheme 语言。 ...
    

    作为Lisp 变体,Scheme 是一门非常简洁的计算语言,使用它的编程人员可以摆脱语言本身的复杂性,把注意力集中到更重要的问题上,从而使语言真正成为解决问题的工具。本文分为上、 两部分来介绍 scheme 语言。

    一.Scheme语言的特点

    Scheme语言是LISP语言的一个方言(或说成变种),它诞生于1975年的MIT,对于这个有近三十年历史的编程语言来说,它并没有象C++,java,C#那样受到商业领域的青睐,在国内更是显为人知。但它在国外的计算机教育领域内却是有着广泛应用的,有很多人学的第一门计算机语言就是Scheme语言。

    它是一个小巧而又强大的语言,作为一个多用途的编程语言,它可以作为脚本语言使用,也可以作为应用软件的扩展语言来使用,它具有元语言特性,还有很多独到的特色,以致于它被称为编程语言中的"皇后"。

    下面是洪峰对Scheme语言的编程特色的归纳:

    • 词法定界(Lexical Scoping)
    • 动态类型(Dynamic Typing)
    • 良好的可扩展性
    • 尾递归(Tail Recursive)
    • 函数可以作为值返回
    • 支持一流的计算连续
    • 传值调用(passing-by-value)
    • 算术运算相对独立

    本文的目的是让有编程基础(那怕是一点点)的朋友能尽快的掌握Scheme语言的语法规则,如果您在读完本文后,发现自己已经会用Scheme语言了,那么我的目的就达到了。


    二.Scheme语言的标准与实现

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

    Scheme语言的语法规则的第5次修正稿,1998年制定,即Scheme语言的现行标准,目前大多数Scheme语言的实现都将达到或遵循此标准,并且几乎都加入了一些属于自己的扩展特色。

    Guile (GNU's extension language)

    Guile是GNU工程的一个项目,它是GNU扩展语言库,它也是Scheme语言的一个具体实现;如果你将它作为一个库打包,可以把它链接到你的应用程序中去,使你的应用程序具有自己的脚本语言,这个脚本语言目前就是Scheme语言。

    Guile可以在LINUX和一些UNIX系统上运行,下面是简单的安装过程:

    下载guile-1.6.4版,文件名为guile-1.6.4.tar.gz,执行下面的命令:

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

    如此,即可以执行命令guile,进入guile>提示符状态,输入调试Scheme程序代码了,本文的所有代码都是在guile下调试通过。

    其它实现

    除了Guile外,Scheme语言的实现还有很多,如:GNU/MIT-Scheme, SCI,Scheme48,DrScheme等,它们大多是开源的,可以自由下载安装使用,并且跨平台的实现也很多。你会发现既有象basic的Scheme语言解释器,也有将Scheme语言编译成C语言的编译器,也有象JAVA那样将Scheme语言代码编译成虚拟机代码的编译器。


    三.基本概念

    注释

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

    		; this is a scheme comment line.

    标准的Scheme语言定义中没有多行注释,不过在它的实现中几乎都有。在Guile中就有多行注释,以符号组合"#!"开始,以相反的另一符号组合"!#"结束,其中内容为注释,如:

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

    注意的是,符号组合"#!"和"!#"一定分做两行来写。

    Scheme用做脚本语言

    Scheme语言可以象sh,perl,python等语言那样作为一种脚本语言来使用,用它来编写可执行脚本,在Linux中如果通过Guile用Scheme语言写可执行脚本,它的第一行和第二行一般是类似下面的内容:

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

    这样的话代码在运行时会自动调用Guile来解释执行,标准的文件尾缀是".scm"。

    块(form)

    块(form)是Scheme语言中的最小程序单元,一个Scheme语言程序是由一个或多个form构成。没有特殊说明的情况下 form 都由小括号括起来,形如:

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

    一个 form 也可以是一个表达式,一个变量定义,也可以是一个过程。

    form嵌套

    Scheme语言中允许form的嵌套,这使它可以轻松的实现复杂的表达式,同时也是一种非常有自己特色的表达式。 下图示意了嵌套的稍复杂一点的表达式的运算过程:

    变量定义

    可以用define来定义一个变量,形式如下:
    (define 变量名 值)

    如: (define x 123) ,定义一个变量x,其值为123。

    更改变量的值

    可以用set!来改变变量的值,格式如下:
    (set! 变量名 值)

    如: (set! x "hello") ,将变量x的值改为"hello" 。

    Scheme语言是一种高级语言,和很多高级语言(如python,perl)一样,它的变量类型不是固定的,可以随时改变。


    四.数据类型

    1. 简单数据类型

    逻辑型(boolean)

    最基本的数据类型,也是很多计算机语言中都支持的最简单的数据类型,只能取两个值:#t,相当于其它计算机语言中的 TRUE;#f,相当于其它计算机语言中的 FALSE。

    Scheme语言中的boolean类型只有一种操作:not。其意为取相反的值,即:

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

    not的引用,与逻辑非运算操作类似

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

    从上面的操作中可以看出来,只要not后面的参数不是逻辑型,其返回值均为#f。

    数字型(number)

    它又分为四种子类型:整型(integer),有理数型(rational),实型(real),复数型(complex);它们又被统一称为数字类型(number)。

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

    Scheme语言中,数字类型的数据还可以按照进制分类,即二进制,八进制,十进制和十六进制,在外观形式上它们分别以符号组合 #b、 #o、 #d、 #x 来作为表示数字进制类型的前缀,其中表示十进制的#d可以省略不写,如:二进制的 #b1010 ,八进制的 #o567,十进制的123或 #d123,十六进制的 #x1afc 。

    Scheme语言的这种严格按照数学定理来为数字类型进行分类的方法可以看出Scheme语言里面渗透着很深的数学思想,Scheme语言是由数学家们创造出来的,在这方面表现得也比较鲜明。

    字符型(char)

    Scheme语言中的字符型数据均以符号组合 "#\" 开始,表示单个字符,可以是字母、数字或"[ ! $ % & * + - . / : %lt; = > ? @ ^ _ ~ ]"等等其它字符,如:
    #\A 表示大写字母A,#\0表示字符0,
    其中特殊字符有:#\space 表示空格符和 #\newline 表示换行符。

    符号型(symbol)

    符号类型是Scheme语言中有多种用途的符号名称,它可以是单词,用括号括起来的多个单词,也可以是无意义的字母组合或符号组合,它在某种意义上可以理解为C中的枚举类型。看下面的操作:

    guile> (define a (quote xyz))  ;  定义变量a为符号类型,值为xyz
    guile> a
    xyz
    guile> (define xyz 'a)  ; 定义变量xyz为符号类型,值为a
    guile> xyz
    a

    此处也说明单引号' 与quote是等价的,并且更简单一些。符号类型与字符串不同的是符号类型不能象字符串那样可以取得长度或改变其中某一成员字符的值,但二者之间可以互相转换。

    2. 复合数据类型

    可以说复合数据类型是由基本的简单数据类型通过某种方式加以组合形成的数据类型,特点是可以容纳多种或多个单一的简单数据类型的数据,多数是基于某一种数学模型创建的。

    字符串(string) 由多个字符组成的数据类型,可以直接写成由双引号括起的内容,如:"hello" 。下面是Guile中的字符串定义和相关操作:

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

    字符串还可以用下面的形式定义:

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

    字符串中出现引号时用反斜线加引号代替,如:"abc\"def" 。

    点对(pair)

    我把它译成"点对",它是一种非常有趣的类型,也是一些其它类型的基础类型,它是由一个点和被它分隔开的两个所值组成的。形如: (1 . 2) 或 (a . b) ,注意的是点的两边有空格。

    这是最简单的复合数据类型,同是它也是其它复合数据类型的基础类型,如列表类型(list)就是由它来实现的。

    按照Scheme语言说明中的惯例,以下我们用符号组合 "=>" 来表示表达式的值。

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

    其中在点前面的值被称为 car ,在点后面的值被称为 cdr ,car和cdr同时又成为取pair的这两个值的过程,如:

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

    还可以用set-car! 和 set-cdr! 来分别设定这两个值:

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

    如此,以前定义的 p 又变成了 ("hello" . "good") 这个样子了。

    列表(list)

    列表是由多个相同或不同的数据连续组成的数据类型,它是编程中最常用的复合数据类型之一,很多过程操作都与它相关。下面是在Guile中列表的定义和相关操作:

    guile> (define la (list 1 2 3 4 ))
    guile> la
    (1 2 3 4)
    guile> (length la)  ; 取得列表的长度
    4
    guile> (list-ref la 3)  ; 取得列表第3项的值(从0开始)
    4
    guile> (list-set! la 2 99)  ; 设定列表第2项的值为99
    99
    guile> la
    (1 2 99 4)
    guile> (define y (make-list 5 6))  ;创建列表
    guile> y
    (6 6 6 6 6)

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

    列表与pair的关系

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

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

    由上可见,a本来是我们上面定义的点对,最后形成的却是列表。事实上列表是在点对的基础上形成的一种特殊格式。

    再看下面的代码:

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

    由此可见,list是pair的子类型,list一定是一个pair,而pair不是list。

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

    其cdr又是一个列表,可见用于pair的操作过程大多可以用于list。

    	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)

    上在的操作中用到的cadr,cdddr等过程是专门对PAIR型数据再复合形成的数据操作的过程,最多可以支持在中间加四位a或d,如cdddr,caaddr等。

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

    这个列表可以由pair定义为如下形式:

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

    而列表的实际内容则为:(a b c d)

    由pair类型还可以看出它可以轻松的表示树型结构,尤其是标准的二叉树。

    向量(vector)

    可以说是一个非常好用的类型 ,是一种元素按整数来索引的对象,异源的数据结构,在占用空间上比同样元素的列表要少,在外观上:

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

    vector是一种比较常用的复合类型,它的元素索引从0开始,至第 n-1 结束,这一点有点类似C语言中的数组。

    关于向量表(vector)的常用操作过程:

    guile> (define v (vector 1 2 3 4 5))
    guile> v
    #(1 2 3 4 5)
    guile> (vector-ref v 0)	; 求第n个变量的值
    1
    guile> (vector-length v)  ; 求vector的长度
    5
    guile> (vector-set! v 2 "abc")  ; 设定vector第n个元素的值
    guile> v
    #(1 2 "abc" 4 5)
    guile> (define x (make-vector 5 6))  ; 创建向量表
    guile> x
    #(6 6 6 6 6)

    make-vector用来创建一个向量表,第一个参数是数量,后一个参数是添充的值,这和列表中的make-list非常相似。

    我们可以看出,在Scheme语言中,每种数据类型都有一些基本的和它相关的操作过程,如字符串,列表等相关的操作,这些操作过程都很有规律,过程名的单词之间都用-号隔开,很容易理解。对于学过C++的朋友来说,更类似于某个对象的方法,只不过表现的形式不同了。

    3. 类型的判断、比较、运算、转换与方法

    类型判断

    Scheme语言中所有判断都是用类型名加问号再加相应的常量或变量构成,形如:

    (类型? 变量)

    Scheme语言在类型定义中有比较严格的界定,如在C语言等一些语言中数字0来代替逻辑类型数据False,在Scheme语言中是不允许的。

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

    逻辑型:

    (boolean? #t) => #t
    (boolean? #f) => #t	因为#t和#f都是boolean类型,所以其值为#t
    (boolean? 2)  => #f	因为2是数字类型,所以其值为 #f

    字符型

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

    数字型

    (integer? 1)		=> #t
    (integer? 2345)	=> #t
    (integer? -90)		=> #t	以上三个数均为整数
    (integer? 8.9)		=> #f   8.9不整数
    (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意为空类型,它表示为 '() ,即括号里什么都没有的符号
    (null? 5)		=> #f
    (define x 123)		定义变量x其值为123
    (symbol? x)		=> #f
    (symbol? 'x)		=> #t  ; 此时 'x 为符号x,并不表示变量x的值

    在Scheme语言中如此众多的类型判断功能,使得Scheme语言有着非常好的自省功能。即在判断过程的参数是否附合过程的要求。

    比较运算

    Scheme语言中可以用<,>,<=,>=,= 来判断数字类型值或表达式的关系,如判断变量x是否等于零,它的形式是这样的:(= x 0) ,如x的值为0则表达式的值为#t,否则为#f。

    还有下面的操作:

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

    以上两个form功能相同,说明 eqv? 也可以用于数字的判断。

    在Scheme语言中有三种相等的定义,两个变量正好是同一个对象;两个对象具有相同的值;两个对象具有相同的结构并且结构中的内容相同。除了上面提到的符号判断过程和eqv?外,还有eq?和equal?也是判断是否相等的过程。

    eq?,eqv?,equal?

    eq?,eqv?和equal?是三个判断两个参数是否相等的过程,其中eq?和eqv?的功能基本是相同的,只在不同的Scheme语言中表现不一样。

    eq?是判断两个参数是否指向同一个对象,如果是才返回#t;equal?则是判断两个对象是否具有相同的结构并且结构中的内容是否相同,它用eq?来比较结构中成员的数量;equal?多用来判断点对,列表,向量表,字符串等复合结构数据类型。

    guile> (define v (vector 3 4 5))
    guile> (define w #(3 4 5))  ; w和v都是vector类型,具有相同的值#(3 4 5)
    guile> (eq? v w)
    #f					; 此时w和v是两个对象
    guile> (equal? v w)
    #t                  ; 符合equal?的判断要求

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

    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)    ; 不是同一个对象
    #f
    guile> (equal? x z)  ; 结构相同,内容相同,所以返回#t
    #t

    算术运算

    Scheme语言中的运算符有:
    + , - , * , / 和 expt (指数运算)
    其中 - 和 / 还可以用于单目运算,如:

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

    此外还有许多扩展的库提供了很多有用的过程,

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

    除了max,min,abs外,还有很多数学运算过程,这要根据你用的Scheme语言的运行环境有关,不过它们大多是相同的。在R5RS中规定了很多运算过程,在R5RS的参考资料中可以很容易找到。

    转换

    Scheme语言中用符号组合"->"来标明类型间的转换(很象C语言中的指针)的过程,就象用问号来标明类型判断过程一样。下面是一些常见的类型转换过程:

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

    五.过程定义

    过程(Procedure)

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

    guile> +
    #<primitive-procedure +>

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

    define不仅可以定义变量,还可以定义过程,因在Scheme语言中过程(或函数)都是一种数据类型,所以都可以通过define来定义。不同的是标准的过程定义要使用lambda这一关键字来标识。

    Lambda关键字

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

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

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

    此过程需要一个参数,其功能为返回此参数加5 的值,如:

    	    (add5 11) => 16

    下面是简单的求平方过程square的定义:

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

    与lambda相同的另一种方式

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

    如下面操作:

    		(define (add6 x) (+ x 6))
    		add6
    		#<procedure: add6 (x)> 说明add6是一个过程,它有一个参数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

    更多的过程定义

    上面定义的过程fun有三个参数,其中第一个参数proc也是一个操作过程(因为在Scheme语言中过程也是一种数据,可以作为过程的参数),另外两个参数是数值,所以会出现上面的调用结果。

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

    继续上面操作,我们定义一个过程add,将add作为参数传递给fun过程,得出和(fun + 100 200)相同的结果。

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

    上面的 (lambda(x) (+ x x)) 事实上是简单的过程定义,在后面直接加上操作参数5,得出结果10,这样实现了匿名过程,直接用过程定义来操作参数,得出运算结果。

    通过上面的操作,相信你已初步了解了过程的用法。 既然过程是一种数据类型,所以将过程作为过程的参数是完全可以的。以下过程为判断参数是否为过程,给出一个参数,用 procedure? 来判断参数是否为过程,采用if结构(关于if结构见下面的介绍):

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

    上面的过程就体现了Scheme语言的参数自省(辨别)能力,'0'是数字型,所以返回notaprocedure;而'+'是一个最基础的操作过程,所以返回isaprocedure。

    过程的嵌套定义

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

    如下面的代码的最终结果是50:

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

    此时过程add只在fix过程内部起做用,这事实上涉及了过程和变量的绑定,可以参考下面的关于过程绑定(let,let* 和letrec)的介绍。

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

    熟悉了 scheme 基本概念、数据类型和过程(函数)后, 下一部分我们来学习 scheme 的结构、递归调用和其他扩展功能。

    展开全文
  • scheme 语言概述

    千次阅读 2015-10-07 02:14:09
    Scheme语言是LISP语言的一个方言(或说成变种),它诞生于1975年的MIT,对于这个有近三十年历史的编程语言来 说,它并没有象C++,java,C#那样受到商业领域的青睐,在国内更是显为人知。但它在国外的计算机教育领域内...
    Scheme语言是LISP语言的一个方言(或说成变种),它诞生于1975年的MIT,对于这个有近三十年历史的编程语言来 说,它并没有象C++,java,C#那样受到商业领域的青睐,在国内更是显为人知。但它在国外的计算机教育领域内却是有着广泛应用的,有很多人学的第一 门计算机语言就是Scheme语言。

    作为Lisp 变体,Scheme 是一门非常简洁的计算语言,使用它的编程人员可以摆脱语言本身的复杂性,把注意力集中到更重要的问题上,从而使语言真正成为解决问题的工具。

    一.Scheme语言的特点

    Scheme 语言是LISP语言的一个方言(或说成变种),它诞生于1975年的MIT,对于这个有近三十年历史的编程语言来说,它并没有象C++,java,C#那 样受到商业领域的青睐,在国内更是显为人知。但它在国外的计算机教育领域内却是有着广泛应用的,有很多人学的第一门计算机语言就是Scheme语言。

    它是一个小巧而又强大的语言,作为一个多用途的编程语言,它可以作为脚本语言使用,也可以作为应用软件的扩展语言来使用,它具有元语言特性,还有很多独到的特色,以致于它被称为编程语言中的"皇后"。

    • 词法定界(Lexical Scoping)
    • 动态类型(Dynamic Typing)
    • 良好的可扩展性
    • 尾递归(Tail Recursive)
    • 函数可以作为值返回
    • 支持一流的计算连续
    • 传值调用(passing-by-value)
    • 算术运算相对独立

    本文的目的是让有编程基础(那怕是一点点)的朋友能尽快的掌握Scheme语言的语法规则,如果您在读完本文后,发现自己已经会用Scheme语言了,那么我的目的就达到了。







    二.Scheme语言的标准与实现

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

    Scheme语言的语法规则的第5次修正稿,1998年制定,即Scheme语言的现行标准,目前大多数Scheme语言的实现都将达到或遵循此标准,并且几乎都加入了一些属于自己的扩展特色。

    Guile (GNU's extension language)

    Guile是GNU工程的一个项目,它是GNU扩展语言库,它也是Scheme语言的一个具体实现;如果你将它作为一个库打包,可以把它链接到你的应用程序中去,使你的应用程序具有自己的脚本语言,这个脚本语言目前就是Scheme语言。

    Guile可以在LINUX和一些UNIX系统上运行,下面是简单的安装过程:

    下载guile-1.6.4版,文件名为guile-1.6.4.tar.gz,执行下面的命令:

    tar xvfz guile-1.6.4.tar.gz<br style="word-wrap:break-word" />cd guile-1.6.4<br style="word-wrap:break-word" />./configure<br style="word-wrap:break-word" />make<br style="word-wrap:break-word" />make install<br style="word-wrap:break-word" />

    如此,即可以执行命令guile,进入guile>提示符状态,输入调试Scheme程序代码了,本文的所有代码都是在guile下调试通过。

    其它实现

    除 了Guile外,Scheme语言的实现还有很多,如:GNU/MIT-Scheme, SCI,Scheme48,DrScheme等,它们大多是开源的,可以自由下载安装使用,并且跨平台的实现也很多。你会发现既有象basic的 Scheme语言解释器,也有将Scheme语言编译成C语言的编译器,也有象JAVA那样将Scheme语言代码编译成虚拟机代码的编译器。







    三.基本概念

    注释

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

    		; this is a scheme comment line.<br style="word-wrap:break-word" />		

    标准的Scheme语言定义中没有多行注释,不过在它的实现中几乎都有。在Guile中就有多行注释,以符号组合"#!"开始,以相反的另一符号组合"!#"结束,其中内容为注释,如:

    #!<br style="word-wrap:break-word" />there are scheme comment area.<br style="word-wrap:break-word" />you can write mulity lines here . <br style="word-wrap:break-word" />!#<br style="word-wrap:break-word" />

    注意的是,符号组合"#!"和"!#"一定分做两行来写。

    Scheme用做脚本语言

    Scheme语言可以象sh,perl,python等语言那样作为一种脚本语言来使用,用它来编写可执行脚本,在Linux中如果通过Guile用Scheme语言写可执行脚本,它的第一行和第二行一般是类似下面的内容:

    #! /usr/local/bin/guile -s<br style="word-wrap:break-word" />!#

    这样的话代码在运行时会自动调用Guile来解释执行,标准的文件尾缀是".scm"。

    块(form)

    块(form)是Scheme语言中的最小程序单元,一个Scheme语言程序是由一个或多个form构成。没有特殊说明的情况下 form 都由小括号括起来,形如:

    (define x 123)<br style="word-wrap:break-word" />(+ 1 2)<br style="word-wrap:break-word" />(* 4 5 6)<br style="word-wrap:break-word" />(display "hello world")<br style="word-wrap:break-word" />

    一个 form 也可以是一个表达式,一个变量定义,也可以是一个过程。

    form嵌套

    Scheme语言中允许form的嵌套,这使它可以轻松的实现复杂的表达式,同时也是一种非常有自己特色的表达式。 下图示意了嵌套的稍复杂一点的表达式的运算过程:



     

    变量定义

    可以用define来定义一个变量,形式如下: 
    (define 变量名 值)

    如: (define x 123) ,定义一个变量x,其值为123。

    更改变量的值

    可以用set!来改变变量的值,格式如下: 
    (set! 变量名 值)

    如: (set! x "hello") ,将变量x的值改为"hello" 。

    Scheme语言是一种高级语言,和很多高级语言(如python,perl)一样,它的变量类型不是固定的,可以随时改变。







    四.数据类型

    1. 简单数据类型

    逻辑型(boolean)

    最基本的数据类型,也是很多计算机语言中都支持的最简单的数据类型,只能取两个值:#t,相当于其它计算机语言中的 TRUE;#f,相当于其它计算机语言中的 FALSE。

    Scheme语言中的boolean类型只有一种操作:not。其意为取相反的值,即:

    		(not #f) => #t<br style="word-wrap:break-word" />		(not #t) => #f<br style="word-wrap:break-word" />		

    not的引用,与逻辑非运算操作类似

    guile> (not 1)<br style="word-wrap:break-word" />#f<br style="word-wrap:break-word" />guile> (not (list 1 2 3))<br style="word-wrap:break-word" />#f<br style="word-wrap:break-word" />guile> (not 'a)<br style="word-wrap:break-word" />#f<br style="word-wrap:break-word" />

    从上面的操作中可以看出来,只要not后面的参数不是逻辑型,其返回值均为#f。

    数字型(number)

    它又分为四种子类型:整型(integer),有理数型(rational),实型(real),复数型(complex);它们又被统一称为数字类型(number)。

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

    Scheme 语言中,数字类型的数据还可以按照进制分类,即二进制,八进制,十进制和十六进制,在外观形式上它们分别以符号组合 #b、 #o、 #d、 #x 来作为表示数字进制类型的前缀,其中表示十进制的#d可以省略不写,如:二进制的 #b1010 ,八进制的 #o567,十进制的123或 #d123,十六进制的 #x1afc 。

    Scheme语言的这种严格按照数学定理来为数字类型进行分类的方法可以看出Scheme语言里面渗透着很深的数学思想,Scheme语言是由数学家们创造出来的,在这方面表现得也比较鲜明。

    字符型(char)

    Scheme语言中的字符型数据均以符号组合 "#\" 开始,表示单个字符,可以是字母、数字或"[ ! $ % & * + - . / : %lt; = > ? @ ^ _ ~ ]"等等其它字符,如: 
    #\A 表示大写字母A,#\0表示字符0, 
    其中特殊字符有:#\space 表示空格符和 #\newline 表示换行符。

    符号型(symbol)

    符号类型是Scheme语言中有多种用途的符号名称,它可以是单词,用括号括起来的多个单词,也可以是无意义的字母组合或符号组合,它在某种意义上可以理解为C中的枚举类型。看下面的操作:

    guile> (define a (quote xyz))  ;  定义变量a为符号类型,值为xyz<br style="word-wrap:break-word" />guile> a<br style="word-wrap:break-word" />xyz<br style="word-wrap:break-word" />guile> (define xyz 'a)  ; 定义变量xyz为符号类型,值为a<br style="word-wrap:break-word" />guile> xyz<br style="word-wrap:break-word" />a<br style="word-wrap:break-word" />

    此处也说明单引号' 与quote是等价的,并且更简单一些。符号类型与字符串不同的是符号类型不能象字符串那样可以取得长度或改变其中某一成员字符的值,但二者之间可以互相转换。

    2. 复合数据类型

    可以说复合数据类型是由基本的简单数据类型通过某种方式加以组合形成的数据类型,特点是可以容纳多种或多个单一的简单数据类型的数据,多数是基于某一种数学模型创建的。

    字符串(string) 由多个字符组成的数据类型,可以直接写成由双引号括起的内容,如:"hello" 。下面是Guile中的字符串定义和相关操作:

    guile> (define name "tomson")<br style="word-wrap:break-word" />guile> name<br style="word-wrap:break-word" />"tomson"<br style="word-wrap:break-word" />guile> (string-length name)  ; 取字符串的长度<br style="word-wrap:break-word" />6<br style="word-wrap:break-word" />guile> (string-set! name 0 #\g)  ; 更改字符串首字母(第0个字符)为小写字母g (#\g)<br style="word-wrap:break-word" />guile> name<br style="word-wrap:break-word" />"gomson"<br style="word-wrap:break-word" />guile> (string-ref name 3)  ; 取得字符串左侧第3个字符(从0开始)<br style="word-wrap:break-word" />#\s<br style="word-wrap:break-word" />

    字符串还可以用下面的形式定义:

    guile> (define other (string #\h #\e #\l #\l #\o ))<br style="word-wrap:break-word" />guile> other<br style="word-wrap:break-word" />"hello"<br style="word-wrap:break-word" />

    字符串中出现引号时用反斜线加引号代替,如:"abc\"def" 。

    点对(pair)

    我把它译成"点对",它是一种非常有趣的类型,也是一些其它类型的基础类型,它是由一个点和被它分隔开的两个所值组成的。形如: (1 . 2) 或 (a . b) ,注意的是点的两边有空格。

    这是最简单的复合数据类型,同是它也是其它复合数据类型的基础类型,如列表类型(list)就是由它来实现的。

    按照Scheme语言说明中的惯例,以下我们用符号组合 "=>" 来表示表达式的值。

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

    其中在点前面的值被称为 car ,在点后面的值被称为 cdr ,car和cdr同时又成为取pair的这两个值的过程,如:

    (define p (cons 4 5))	=> (4 . 5)<br style="word-wrap:break-word" />(car p)			=> 4<br style="word-wrap:break-word" />(cdr p)			=> 5<br style="word-wrap:break-word" />

    还可以用set-car! 和 set-cdr! 来分别设定这两个值:

    (set-car! p "hello")<br style="word-wrap:break-word" />(set-cdr! p "good")<br style="word-wrap:break-word" />

    如此,以前定义的 p 又变成了 ("hello" . "good") 这个样子了。

    列表(list)

    列表是由多个相同或不同的数据连续组成的数据类型,它是编程中最常用的复合数据类型之一,很多过程操作都与它相关。下面是在Guile中列表的定义和相关操作:

    guile> (define la (list 1 2 3 4 ))<br style="word-wrap:break-word" />guile> la<br style="word-wrap:break-word" />(1 2 3 4)<br style="word-wrap:break-word" />guile> (length la)  ; 取得列表的长度<br style="word-wrap:break-word" />4<br style="word-wrap:break-word" />guile> (list-ref la 3)  ; 取得列表第3项的值(从0开始)<br style="word-wrap:break-word" />4<br style="word-wrap:break-word" />guile> (list-set! la 2 99)  ; 设定列表第2项的值为99<br style="word-wrap:break-word" />99<br style="word-wrap:break-word" />guile> la<br style="word-wrap:break-word" />(1 2 99 4)<br style="word-wrap:break-word" />guile> (define y (make-list 5 6))  ;创建列表<br style="word-wrap:break-word" />guile> y<br style="word-wrap:break-word" />(6 6 6 6 6)<br style="word-wrap:break-word" />

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

    列表与pair的关系

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

    guile> (define a (cons 1 (cons 2 (cons 3 '()))))<br style="word-wrap:break-word" />guile> a<br style="word-wrap:break-word" />(1 2 3)<br style="word-wrap:break-word" />

    由上可见,a本来是我们上面定义的点对,最后形成的却是列表。事实上列表是在点对的基础上形成的一种特殊格式。

    再看下面的代码:

    guile> (define ls (list 1 2 3 4))<br style="word-wrap:break-word" />guile> ls<br style="word-wrap:break-word" />(1 2 3 4)<br style="word-wrap:break-word" />guile> (list? ls)<br style="word-wrap:break-word" />#t<br style="word-wrap:break-word" />guile> (pair? ls)<br style="word-wrap:break-word" />#t<br style="word-wrap:break-word" />

    由此可见,list是pair的子类型,list一定是一个pair,而pair不是list。

    guile> (car ls)<br style="word-wrap:break-word" />1<br style="word-wrap:break-word" />guile> (cdr ls)<br style="word-wrap:break-word" />(2 3 4)<br style="word-wrap:break-word" />

    其cdr又是一个列表,可见用于pair的操作过程大多可以用于list。

    	guile> (cadr ls)   ; 此"点对"对象的cdr的car<br style="word-wrap:break-word" />2<br style="word-wrap:break-word" />guile> (cddr ls)   ; 此"点对"对象的cdr的cdr<br style="word-wrap:break-word" />(3 4)<br style="word-wrap:break-word" />guile> (caddr ls)   ; 此"点对"对象的cdr的cdr的car<br style="word-wrap:break-word" />3<br style="word-wrap:break-word" />guile> (cdddr ls)   ; 此"点对"对象的cdr的cdr的cdr<br style="word-wrap:break-word" />(4)<br style="word-wrap:break-word" />	

    上在的操作中用到的cadr,cdddr等过程是专门对PAIR型数据再复合形成的数据操作的过程,最多可以支持在中间加四位a或d,如cdddr,caaddr等。

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



     

    这个列表可以由pair定义为如下形式:

    (define x (cons 'a (cons 'b (cons 'c (cons 'd '())))))<br style="word-wrap:break-word" />

    而列表的实际内容则为:(a b c d)

    由pair类型还可以看出它可以轻松的表示树型结构,尤其是标准的二叉树。

    向量(vector)

    可以说是一个非常好用的类型 ,是一种元素按整数来索引的对象,异源的数据结构,在占用空间上比同样元素的列表要少,在外观上:

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

    vector是一种比较常用的复合类型,它的元素索引从0开始,至第 n-1 结束,这一点有点类似C语言中的数组。

    关于向量表(vector)的常用操作过程:

    guile> (define v (vector 1 2 3 4 5))<br style="word-wrap:break-word" />guile> v<br style="word-wrap:break-word" />#(1 2 3 4 5)<br style="word-wrap:break-word" />guile> (vector-ref v 0)	; 求第n个变量的值<br style="word-wrap:break-word" />1<br style="word-wrap:break-word" />guile> (vector-length v)  ; 求vector的长度<br style="word-wrap:break-word" />5<br style="word-wrap:break-word" />guile> (vector-set! v 2 "abc")  ; 设定vector第n个元素的值<br style="word-wrap:break-word" />guile> v<br style="word-wrap:break-word" />#(1 2 "abc" 4 5)<br style="word-wrap:break-word" />guile> (define x (make-vector 5 6))  ; 创建向量表<br style="word-wrap:break-word" />guile> x<br style="word-wrap:break-word" />#(6 6 6 6 6)<br style="word-wrap:break-word" />

    make-vector用来创建一个向量表,第一个参数是数量,后一个参数是添充的值,这和列表中的make-list非常相似。

    我们可以看出,在Scheme语言中,每种数据类型都有一些基本的和它相关的操作过程,如字符串,列表等相关的操作,这些操作过程都很有规律,过程名的单词之间都用-号隔开,很容易理解。对于学过C++的朋友来说,更类似于某个对象的方法,只不过表现的形式不同了。

    3. 类型的判断、比较、运算、转换与方法

    类型判断

    Scheme语言中所有判断都是用类型名加问号再加相应的常量或变量构成,形如:

    (类型? 变量)<br style="word-wrap:break-word" />

    Scheme语言在类型定义中有比较严格的界定,如在C语言等一些语言中数字0来代替逻辑类型数据False,在Scheme语言中是不允许的。

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

    逻辑型:

    (boolean? #t) => #t<br style="word-wrap:break-word" />(boolean? #f) => #t	因为#t和#f都是boolean类型,所以其值为#t<br style="word-wrap:break-word" />(boolean? 2)  => #f	因为2是数字类型,所以其值为 #f<br style="word-wrap:break-word" />

    字符型

    (char? #\space)	=> #t<br style="word-wrap:break-word" />(char? #\newline)	=> #t	以上两个特殊字符:空格和换行<br style="word-wrap:break-word" />(char? #\f)		=> #t	小写字母 f<br style="word-wrap:break-word" />(char? #\;)		=> #t	分号 ;<br style="word-wrap:break-word" />(char? #\5)		=> #t	字符 5	,以上这些都是正确的,所以返回值都是 #t<br style="word-wrap:break-word" />(char? 5)		=> #f	这是数字 5 ,不是字符类型,所以返回 #f<br style="word-wrap:break-word" />

    数字型

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

    其它型

    (null? '())		=> #t  ; null意为空类型,它表示为 '() ,即括号里什么都没有的符号<br style="word-wrap:break-word" />(null? 5)		=> #f<br style="word-wrap:break-word" />(define x 123)		定义变量x其值为123<br style="word-wrap:break-word" />(symbol? x)		=> #f<br style="word-wrap:break-word" />(symbol? 'x)		=> #t  ; 此时 'x 为符号x,并不表示变量x的值<br style="word-wrap:break-word" />

    在Scheme语言中如此众多的类型判断功能,使得Scheme语言有着非常好的自省功能。即在判断过程的参数是否附合过程的要求。

    比较运算

    Scheme语言中可以用<,>,<=,>=,= 来判断数字类型值或表达式的关系,如判断变量x是否等于零,它的形式是这样的:(= x 0) ,如x的值为0则表达式的值为#t,否则为#f。

    还有下面的操作:

    (eqv? 34 34)   =>  #t<br style="word-wrap:break-word" />(= 34 34)      =>  #t<br style="word-wrap:break-word" />

    以上两个form功能相同,说明 eqv? 也可以用于数字的判断。

    在Scheme语言中有三种相等的定义,两个变量正好是同一个对象;两个对象具有相同的值;两个对象具有相同的结构并且结构中的内容相同。除了上面提到的符号判断过程和eqv?外,还有eq?和equal?也是判断是否相等的过程。

    eq?,eqv?,equal?

    eq?,eqv?和equal?是三个判断两个参数是否相等的过程,其中eq?和eqv?的功能基本是相同的,只在不同的Scheme语言中表现不一样。

    eq?是判断两个参数是否指向同一个对象,如果是才返回#t;equal?则是判断两个对象是否具有相同的结构并且结构中的内容是否相同,它用eq?来比较结构中成员的数量;equal?多用来判断点对,列表,向量表,字符串等复合结构数据类型。

    guile> (define v (vector 3 4 5))<br style="word-wrap:break-word" />guile> (define w #(3 4 5))  ; w和v都是vector类型,具有相同的值#(3 4 5)<br style="word-wrap:break-word" />guile> (eq? v w)<br style="word-wrap:break-word" />#f					; 此时w和v是两个对象<br style="word-wrap:break-word" />guile> (equal? v w)<br style="word-wrap:break-word" />#t                  ; 符合equal?的判断要求<br style="word-wrap:break-word" />

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

    guile> (define x (make-vector 5 6))<br style="word-wrap:break-word" />guile> x<br style="word-wrap:break-word" />#(6 6 6 6 6)<br style="word-wrap:break-word" />guile> (eq? x x)    ; 是同一个对象,所以返回#t<br style="word-wrap:break-word" />#t<br style="word-wrap:break-word" />guile> (define z (make-vector 5 6))<br style="word-wrap:break-word" />guile> z<br style="word-wrap:break-word" />#(6 6 6 6 6)<br style="word-wrap:break-word" />guile> (eq? x z)    ; 不是同一个对象<br style="word-wrap:break-word" />#f<br style="word-wrap:break-word" />guile> (equal? x z)  ; 结构相同,内容相同,所以返回#t<br style="word-wrap:break-word" />#t<br style="word-wrap:break-word" />

    算术运算

    Scheme语言中的运算符有: 
    + , - , * , / 和 expt (指数运算) 
    其中 - 和 / 还可以用于单目运算,如:

    (- 4)  => -4<br style="word-wrap:break-word" />(/ 4)  => 1/4<br style="word-wrap:break-word" />

    此外还有许多扩展的库提供了很多有用的过程,

    max 求最大 (max 8 89 90 213)  => 213<br style="word-wrap:break-word" />min 求最小 (min 3 4 5 6 7)  => 3<br style="word-wrap:break-word" />abs 求绝对值 (abs -7) ==> 7<br style="word-wrap:break-word" />

    除了max,min,abs外,还有很多数学运算过程,这要根据你用的Scheme语言的运行环境有关,不过它们大多是相同的。在R5RS中规定了很多运算过程,在R5RS的参考资料中可以很容易找到。

    转换

    Scheme语言中用符号组合"->"来标明类型间的转换(很象C语言中的指针)的过程,就象用问号来标明类型判断过程一样。下面是一些常见的类型转换过程:

    guile> (number->string 123)  ; 数字转换为字符串<br style="word-wrap:break-word" />"123"<br style="word-wrap:break-word" />guile> (string->number "456")  ; 字符串转换为数字<br style="word-wrap:break-word" />456<br style="word-wrap:break-word" />guile> (char->integer #\a)   ;字符转换为整型数,小写字母a的ASCII码值为96<br style="word-wrap:break-word" />97<br style="word-wrap:break-word" />guile> (char->integer #\A)  ;大写字母A的值为65<br style="word-wrap:break-word" />65<br style="word-wrap:break-word" />guile> (integer->char 97)  ;整型数转换为字符<br style="word-wrap:break-word" />#\a<br style="word-wrap:break-word" />guile> (string->list "hello")   ;字符串转换为列表<br style="word-wrap:break-word" />(#\h #\e #\l #\l #\o) <br style="word-wrap:break-word" />guile> (list->string (make-list 4 #\a)) ; 列表转换为字符串<br style="word-wrap:break-word" />"aaaa"<br style="word-wrap:break-word" />guile> (string->symbol "good")  ;字符串转换为符号类型<br style="word-wrap:break-word" />good<br style="word-wrap:break-word" />guile> (symbol->string 'better)  ;符号类型转换为字符串<br style="word-wrap:break-word" />"better"<br style="word-wrap:break-word" />







    五.过程定义

    过程(Procedure)

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

    guile> +<br style="word-wrap:break-word" />#<primitive-procedure +><br style="word-wrap:break-word" />

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

    define不仅可以定义变量,还可以定义过程,因在Scheme语言中过程(或函数)都是一种数据类型,所以都可以通过define来定义。不同的是标准的过程定义要使用lambda这一关键字来标识。

    Lambda关键字

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

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

    		(define add5 (lambda (x) (+ x 5)))<br style="word-wrap:break-word" />		

    此过程需要一个参数,其功能为返回此参数加5 的值,如:

    	    (add5 11) => 16<br style="word-wrap:break-word" />	    

    下面是简单的求平方过程square的定义:

    	(define square (lambda (x)  (* x x)))<br style="word-wrap:break-word" />	

    与lambda相同的另一种方式

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

    如下面操作:

    		(define (add6 x) (+ x 6))<br style="word-wrap:break-word" />		add6<br style="word-wrap:break-word" />		#<procedure: add6 (x)> 说明add6是一个过程,它有一个参数x<br style="word-wrap:break-word" />		(add6 23)    => 29<br style="word-wrap:break-word" />		

    再看下面的操作:

    guile> (define fun<br style="word-wrap:break-word" />                (lambda(proc x y)<br style="word-wrap:break-word" />                        (proc x y)))<br style="word-wrap:break-word" />guile> fun<br style="word-wrap:break-word" />#<procedure fun (proc x y)><br style="word-wrap:break-word" />guile> (fun * 5 6)<br style="word-wrap:break-word" />30<br style="word-wrap:break-word" />guile> (fun / 30 3)<br style="word-wrap:break-word" />10<br style="word-wrap:break-word" />

    更多的过程定义

    上面定义的过程fun有三个参数,其中第一个参数proc也是一个操作过程(因为在Scheme语言中过程也是一种数据,可以作为过程的参数),另外两个参数是数值,所以会出现上面的调用结果。

    guile> (define add<br style="word-wrap:break-word" />                (lambda (x y)<br style="word-wrap:break-word" />                        (+ x y)))<br style="word-wrap:break-word" />guile> add<br style="word-wrap:break-word" />#<procedure add (x y)><br style="word-wrap:break-word" />guile> (fun add 100 200)<br style="word-wrap:break-word" />300<br style="word-wrap:break-word" />

    继续上面操作,我们定义一个过程add,将add作为参数传递给fun过程,得出和(fun + 100 200)相同的结果。

    guile> ((lambda (x) (+ x x)) 5)<br style="word-wrap:break-word" />10<br style="word-wrap:break-word" />

    上面的 (lambda(x) (+ x x)) 事实上是简单的过程定义,在后面直接加上操作参数5,得出结果10,这样实现了匿名过程,直接用过程定义来操作参数,得出运算结果。

    通过上面的操作,相信你已初步了解了过程的用法。 既然过程是一种数据类型,所以将过程作为过程的参数是完全可以的。以下过程为判断参数是否为过程,给出一个参数,用 procedure? 来判断参数是否为过程,采用if结构(关于if结构见下面的介绍):

    guile> (define isp<br style="word-wrap:break-word" />            (lambda (x)<br style="word-wrap:break-word" />                     (if (procedure? x) 'isaprocedure 'notaprocedure)))<br style="word-wrap:break-word" />guile> isp<br style="word-wrap:break-word" />#<procedure isp (x)><br style="word-wrap:break-word" />guile> (isp 0)<br style="word-wrap:break-word" />notaprocedure<br style="word-wrap:break-word" />guile> (isp +)<br style="word-wrap:break-word" />isaprocedure<br style="word-wrap:break-word" />

    上面的过程就体现了Scheme语言的参数自省(辨别)能力,'0'是数字型,所以返回notaprocedure;而'+'是一个最基础的操作过程,所以返回isaprocedure。

    过程的嵌套定义

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

    如下面的代码的最终结果是50:

    (define fix <br style="word-wrap:break-word" />	(lambda (x y z)<br style="word-wrap:break-word" />		(define add <br style="word-wrap:break-word" />			(lambda (a b) (+ a b)))<br style="word-wrap:break-word" />		(- x (add y z))))<br style="word-wrap:break-word" />(display (fix 100 20 30))<br style="word-wrap:break-word" />

    此时过程add只在fix过程内部起做用,这事实上涉及了过程和变量的绑定,可以参考下面的关于过程绑定(let,let* 和letrec)的介绍。

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






    我们接着介绍 scheme 的结构、递归调用、变量和过程的绑定、输入输出等功能。

    一.常用结构

    顺序结构

    也可以说成由多个form组成的form,用begin来将多个form放在一对小括号内,最终形成一个form。格式为:(begin form1 form2 …)

    如用Scheme语言写成的经典的helloworld程序是如下样子的:

    (begin <br style="word-wrap:break-word" />	(display "Hello world!")  ; 输出"Hello world!"<br style="word-wrap:break-word" />	(newline))				; 换行<br style="word-wrap:break-word" />

    if结构

    Scheme语言的if结构有两种格式,一种格式为:(if 测试 过程1 过程2),即测试条件成立则执行过程1,否则执行过程2。例如下面代码:

    (if (= x 0) <br style="word-wrap:break-word" />(display "is zero")<br style="word-wrap:break-word" />(display "not zero"))<br style="word-wrap:break-word" />

    还有另一种格式:(if 测试 过程) ,即测试条件成立则执行过程。例如下面代码:

    		(if (< x 100) (display "lower than 100"))<br style="word-wrap:break-word" />

    根据类型判断来实现自省功能,下面代码判断给定的参数是否为字符串:

    (define fun <br style="word-wrap:break-word" />	(lambda ( x )<br style="word-wrap:break-word" />		(if (string? x)<br style="word-wrap:break-word" />			(display "is a string")<br style="word-wrap:break-word" />			(display "not a string"))))<br style="word-wrap:break-word" />

    如执行 (fun 123) 则返回值为"not a string",这样的功能在C++或JAVA中实现的话可能会很费力气。

    cond结构

    Scheme语言中的cond结构类似于C语言中的switch结构,cond的格式为:

    		(cond ((测试) 操作) … (else 操作))<br style="word-wrap:break-word" />

    如下是在Guile中的操作:

    guile> (define w (lambda (x)<br style="word-wrap:break-word" />      (cond ((< x 0) 'lower)<br style="word-wrap:break-word" />           ((> x 0) 'upper)<br style="word-wrap:break-word" />           (else 'equal))))<br style="word-wrap:break-word" />guile> w<br style="word-wrap:break-word" />#<procedure w (x)><br style="word-wrap:break-word" />guile> (w 9)<br style="word-wrap:break-word" />upper<br style="word-wrap:break-word" />guile> (w -8)<br style="word-wrap:break-word" />lower<br style="word-wrap:break-word" />guile> (w 0)<br style="word-wrap:break-word" />equal<br style="word-wrap:break-word" />

    上面程序代码中,我们定义了过程w,它有一个参数x,如果x的值大于0,则返回符号upper,如x的值小于0则返回符号lower,如x 的值为0则返回符号equal。

    cond可以用if形式来写,上面的过程可以如下定义:

    guile> (define ff<br style="word-wrap:break-word" />		     (lambda (x)<br style="word-wrap:break-word" />                    (if (< x 0) 'lower<br style="word-wrap:break-word" />                            (if (> x 0) 'upper 'zero))))<br style="word-wrap:break-word" />guile> ff<br style="word-wrap:break-word" />#<procedure ff (x)><br style="word-wrap:break-word" />guile> (ff 9)<br style="word-wrap:break-word" />upper<br style="word-wrap:break-word" />guile> (ff -9)<br style="word-wrap:break-word" />lower<br style="word-wrap:break-word" />guile> (ff 0)<br style="word-wrap:break-word" />zero<br style="word-wrap:break-word" />

    这在功能上是和cond一样的,可以看出cond实际上是实现了if的一种多重嵌套。

    case结构

    case结构和cond结构有点类似,它的格式为:

    (case (表达式) ((值) 操作)) ... (else 操作)))

    case结构中的值可以是复合类型数据,如列表,向量表等,只要列表中含有表达式的这个结果,则进行相应的操作,如下面的代码:

     (case (* 2 3)<br style="word-wrap:break-word" />  ((2 3 5 7) 'prime)<br style="word-wrap:break-word" />  ((1 4 6 8 9) 'composite))<br style="word-wrap:break-word" />

    上面的例子返回结果是composite,因为列表(1 4 6 8 9)中含有表达式(* 2 3)的结果6;下面是在Guile中定义的func过程,用到了case结构:

    guile> (define func<br style="word-wrap:break-word" />                (lambda (x y)<br style="word-wrap:break-word" />                        (case (* x y)<br style="word-wrap:break-word" />                                ((0) 'zero)<br style="word-wrap:break-word" />                                (else 'nozero))))<br style="word-wrap:break-word" />guile> func<br style="word-wrap:break-word" />#<procedure func (x y)><br style="word-wrap:break-word" />guile> (func 2 3)<br style="word-wrap:break-word" />nozero<br style="word-wrap:break-word" />guile> (func 2 0)<br style="word-wrap:break-word" />zero<br style="word-wrap:break-word" />guile> (func 0 9)<br style="word-wrap:break-word" />zero<br style="word-wrap:break-word" />guile> (func 2 9)<br style="word-wrap:break-word" />nozero<br style="word-wrap:break-word" />

    and结构

    and结构与逻辑与运算操作类似,and后可以有多个参数,只有它后面的参数的表达式的值都为#t时,它的返回值才为#t,否则为#f。看下面的操作:

    guile> (and (boolean? #f) (< 8 12))<br style="word-wrap:break-word" />#t<br style="word-wrap:break-word" />guile> (and (boolean? 2) (< 8 12))<br style="word-wrap:break-word" />#f<br style="word-wrap:break-word" />guile> (and (boolean? 2) (> 8 12))<br style="word-wrap:break-word" />#f<br style="word-wrap:break-word" />

    如果表达式的值都不是boolean型的话,返回最后一个表达式的值,如下面的操作:

    guile> (and (list 1 2 3) (vector 'a 'b 'c))<br style="word-wrap:break-word" />#(a b c)<br style="word-wrap:break-word" />guile> (and 1 2 3 4 )<br style="word-wrap:break-word" />4<br style="word-wrap:break-word" />guile> (and 'e 'd 'c 'b 'a)<br style="word-wrap:break-word" />a<br style="word-wrap:break-word" />

    or结构

    or结构与逻辑或运算操作类似,or后可以有多个参数,只要其中有一个参数的表达式值为#t,其结果就为#t,只有全为#f时其结果才为#f。如下面的操作:

    guile> (or #f #t)<br style="word-wrap:break-word" />#t<br style="word-wrap:break-word" />guile> (or #f #f)<br style="word-wrap:break-word" />#f<br style="word-wrap:break-word" />guile> (or (rational? 22/7) (< 8 12))<br style="word-wrap:break-word" />#t<br style="word-wrap:break-word" />guile> (rational? 22/7)<br style="word-wrap:break-word" />#t<br style="word-wrap:break-word" />guile> (real? 22/7)<br style="word-wrap:break-word" />#t<br style="word-wrap:break-word" />guile> (or (real? 4+5i) (integer? 3.22))<br style="word-wrap:break-word" />#f<br style="word-wrap:break-word" />

    我们还可以用and和or结构来实现较复杂的判断表达式,如在C语言中的表达式:

    ((x > 100) && (y < 100)) 和 ((x > 100) || (y > 100))<br style="word-wrap:break-word" />

    在Scheme中可以表示为:

    guile> (define x 123)<br style="word-wrap:break-word" />guile> (define y 80)<br style="word-wrap:break-word" />guile> (and (> x 100) (< y 100))<br style="word-wrap:break-word" />#t<br style="word-wrap:break-word" />guile> (or (> x 100) (> y 100))<br style="word-wrap:break-word" />#t<br style="word-wrap:break-word" />

    Scheme语言中只有if结构是系统原始提供的,其它的cond,case,and,or,另外还有do,when,unless等都是可以用宏定义的方式来定义的,这一点充分体现了Scheme的元语言特性,关于do,when等结构的使用可以参考R5RS。







    二.递归调用

    用递归实现阶乘

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

    (define  factoral (lambda (x)<br style="word-wrap:break-word" />		  (if (<= x 1) 1<br style="word-wrap:break-word" />		      (* x (factoral (- x 1))))))<br style="word-wrap:break-word" />

    我们可以将下面的调用(factoral 4),即4的阶乘的运算过程图示如下:



     

    以下为factoral过程在Guile中的运行情况:

    guile> (define factoral (lambda (x) (if (<= x 1) 1 (* x (factoral (- x 1))))))<br style="word-wrap:break-word" />guile> factoral<br style="word-wrap:break-word" />#<procedure factoral (x)><br style="word-wrap:break-word" />guile> (factoral 4)<br style="word-wrap:break-word" />24<br style="word-wrap:break-word" />

    另一种递归方式

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

    (define (factoral n)<br style="word-wrap:break-word" />	(define (iter product counter)<br style="word-wrap:break-word" />		(if (> counter n)<br style="word-wrap:break-word" />			product<br style="word-wrap:break-word" />			(iter (* counter product) (+ counter 1))))<br style="word-wrap:break-word" />	(iter 1 1))<br style="word-wrap:break-word" />(display (factoral 4))<br style="word-wrap:break-word" />

    这个定义的功能和上面的完全相同,只是实现的方法不一样了,我们在过程内部实现了一个过程iter,它用counter参数来计数,调用时从1开始累计,这样它的展开过程正好和我们上面的递归过程的从4到1相反,而是从1到4。

    循环的实现

    在Scheme语言中没有循环结构,不过循环结构可以用递归来很轻松的实现(在Scheme语言中只有通过递归才能实现循环)。对于用惯了C语言循环的朋友,在Scheme中可以用递归简单实现:

    guile> (define loop<br style="word-wrap:break-word" />	     (lambda(x y)<br style="word-wrap:break-word" />    	     (if (<= x y)<br style="word-wrap:break-word" />             	(begin (display x) (display #\\space) (set! x (+ x 1))<br style="word-wrap:break-word" />                	(loop x y)))))<br style="word-wrap:break-word" />guile> loop<br style="word-wrap:break-word" />#<procedure loop (x y)><br style="word-wrap:break-word" />guile> (loop 1 10)<br style="word-wrap:break-word" />1 2 3 4 5 6 7 8 9 10<br style="word-wrap:break-word" />

    这只是一种简单的循环定义,过程有两个参数,第一个参数是循环的初始值,第二个参数是循环终止值,每次增加1。相信读者朋友一定会写出更漂亮更实用的循环操作来的。







    三.变量和过程的绑定

    let,let*,letrec

    在多数编程语言中都有关于变量的存在的时限问题,Scheme语言中用let,let*和letrec来确定变量的存在的时限问题,即局部变量和全局变量,一般情况下,全局变量都用define来定义,并放在过程代码的外部;而局部变量则用let等绑定到过程内部使用。

    用let可以将变量或过程绑定在过程的内部,即实现局部变量:

    guile> let<br style="word-wrap:break-word" />#<primitive-macro! let><br style="word-wrap:break-word" />

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

    下面的代码显示了let的用法(注意多了一层括号):

    guile> (let ((x 2) (y 5)) (* x y))<br style="word-wrap:break-word" />10<br style="word-wrap:break-word" />

    它的格式是:(let ((…)…) …),下面是稍复杂的用法:

    guile> (let ((x 5))<br style="word-wrap:break-word" />         (define foo (lambda (y) (bar x y)))<br style="word-wrap:break-word" />         (define bar (lambda (a b) (+ (* a b) a)))<br style="word-wrap:break-word" />         (foo (+ x 3)))<br style="word-wrap:break-word" />45<br style="word-wrap:break-word" />

    以上是Guile中的代码实现情况。它的实现过程大致是:(foo 8) 展开后形成 (bar 5 8),再展开后形成 (+ (* 5 8) 5) ,最后其值为45。

    再看下面的操作:

    guile> (let ((iszero?<br style="word-wrap:break-word" />                (lambda(x)<br style="word-wrap:break-word" />                (if (= x 0) #t #f))))<br style="word-wrap:break-word" />        (iszero? 9))<br style="word-wrap:break-word" />#f<br style="word-wrap:break-word" />guile> (iszero? 0)  ;此时会显示出错信息<br style="word-wrap:break-word" />

    let的绑定在过程内有效,过程外则无效,这和上面提到的过程的嵌套定是一样的,上面的iszero?过程在操作过程内定义并使用的,操作结束后再另行引用则无效,显示过程未定义出错信息。

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

    guile> (let ((x 2) (y 5))<br style="word-wrap:break-word" />       (let* ((x 6)(z (+ x y)))  ;此时x的值已为6,所以z的值应为11,如此最后的值为66<br style="word-wrap:break-word" />       (* z x)))<br style="word-wrap:break-word" />66<br style="word-wrap:break-word" />

    还有letrec,看下面的操作过程:

    guile> (letrec ((even?<br style="word-wrap:break-word" />                (lambda(x)<br style="word-wrap:break-word" />                (if (= x 0) #t<br style="word-wrap:break-word" />                        (odd? (- x 1)))))<br style="word-wrap:break-word" />            (odd?<br style="word-wrap:break-word" />                (lambda(x)<br style="word-wrap:break-word" />                (if (= x 0) #f<br style="word-wrap:break-word" />                        (even? (- x 1))))))<br style="word-wrap:break-word" />        (even? 88))<br style="word-wrap:break-word" />#t<br style="word-wrap:break-word" />

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

    guile> (letrec ((countdown<br style="word-wrap:break-word" />                (lambda (i)<br style="word-wrap:break-word" />                (if (= i 0) 'listoff<br style="word-wrap:break-word" />                        (begin (display i) (display ",")<br style="word-wrap:break-word" />                                (countdown (- i 1)))))))<br style="word-wrap:break-word" />        (countdown 10))<br style="word-wrap:break-word" />10,9,8,7,6,5,4,3,2,1,listoff<br style="word-wrap:break-word" />

    letrec帮助局部过程实现递归的操作,这不仅在letrec绑定的过程内,而且还包括所有初始化的东西,这使得在编写较复杂的过程中经常用到letrec,也成了理解它的一个难点。

    apply

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

    guile> (apply + (list 2 3 4))<br style="word-wrap:break-word" />9<br style="word-wrap:break-word" />guile> (define sum<br style="word-wrap:break-word" />           (lambda (x )<br style="word-wrap:break-word" />                  (apply + x)))  ; 定义求和过程<br style="word-wrap:break-word" />guile> sum<br style="word-wrap:break-word" />#<procedure sum (x)><br style="word-wrap:break-word" />guile> (define ls (list 2 3 4 5 6))<br style="word-wrap:break-word" />guile> ls<br style="word-wrap:break-word" />(2 3 4 5 6)<br style="word-wrap:break-word" />guile> (sum ls)<br style="word-wrap:break-word" />20<br style="word-wrap:break-word" />guile> (define avg<br style="word-wrap:break-word" />          (lambda(x)<br style="word-wrap:break-word" />                 (/ (sum x) (length x))))   ; 定义求平均过程<br style="word-wrap:break-word" />guile> avg<br style="word-wrap:break-word" />#<procedure avg (x)><br style="word-wrap:break-word" />guile> (avg ls)<br style="word-wrap:break-word" />4<br style="word-wrap:break-word" />

    以上定义了求和过程sum和求平均的过程avg,其中求和的过程sum中用到了apply来绑定"+"过程操作到列表,结果返回列表中所有数的总和。

    map

    map的功能和apply有些相似,它的第一个参数也必需是一个过程,随后的参数必需是多个列表,返回的结果是此过程来操作列表后的值,如下面的操作:

    guile> (map + (list 1 2 3) (list 4 5 6))<br style="word-wrap:break-word" />(5 7 9)<br style="word-wrap:break-word" />guile> (map car '((a . b)(c . d)(e . f)))<br style="word-wrap:break-word" />(a c e)<br style="word-wrap:break-word" />

    除了apply,map以外,Scheme 语言中还有很多,诸如:eval,delay,for-each,force,call-with-current-continuation等过程绑定 的操作定义,它们都无一例外的提供了相当灵活的数据处理能力,也就是另初学者望而生畏的算法,当你仔细的体会了运算过程中用到的简直妙不可言的算法后,你 就会发现Scheme语言设计者的思想是多么伟大。







    四.输入输出

    Scheme语言中也提供了相应的输入输出功能,是在C基础上的一种封装。

    端口

    Scheme语言中输入输出中用到了端口的概念,相当于C中的文件指针,也就是Linux中的设备文件,请看下面的操作:

    guile> (current-input-port)<br style="word-wrap:break-word" />#<input: standard input /dev/pts/0> ;当前的输入端口<br style="word-wrap:break-word" />guile> (current-output-port)<br style="word-wrap:break-word" />#<output: standard output /dev/pts/0> ;当前的输出端口<br style="word-wrap:break-word" />

    判断是否为输入输出端口,可以用下面两个过程:input-port? 和output-port? ,其中input-port?用来判断是否为输入端口,output-port?用来判断是否为输出端口。

    open-input-file,open-output-file,close-input-port,close-output-port这四个过程用来打开和关闭输入输出文件,其中打开文件的参数是文件名字符串,关闭文件的参数是打开的端口。

    输入

    打开一个输入文件后,返回的是输入端口,可以用read过程来输入文件的内容:

    guile> (define port (open-input-file "readme"))<br style="word-wrap:break-word" />guile> port<br style="word-wrap:break-word" />#<input: readme 4><br style="word-wrap:break-word" />guile> (read port)<br style="word-wrap:break-word" />GUILE语言<br style="word-wrap:break-word" />

    上面的操作打开了readme文件,并读出了它的第一行内容。此外还可以直接用read过程来接收键盘输入,如下面的操作:

    guile> (read)  ; 执行后即等待键盘输入<br style="word-wrap:break-word" />12345<br style="word-wrap:break-word" />12345<br style="word-wrap:break-word" />guile> (define x (read))  ; 等待键盘输入并赋值给x<br style="word-wrap:break-word" />12345<br style="word-wrap:break-word" />guile> x<br style="word-wrap:break-word" />12345<br style="word-wrap:break-word" />

    以上为用read来读取键入的数字,还可以输入字符串等其它类型数据:

    guile> (define name (read))<br style="word-wrap:break-word" />tomson<br style="word-wrap:break-word" />guile> name<br style="word-wrap:break-word" />tomson<br style="word-wrap:break-word" />guile> (string? name)<br style="word-wrap:break-word" />#f<br style="word-wrap:break-word" />guile> (symbol? name)<br style="word-wrap:break-word" />#t<br style="word-wrap:break-word" />

    此时输入的tomson是一个符号类型,因为字符串是用引号引起来的,所以出现上面的情况。下面因为用引号了,所以(string? str)返回值为#t 。

    guile> (define str (read))<br style="word-wrap:break-word" />"Johnson"<br style="word-wrap:break-word" />guile> str<br style="word-wrap:break-word" />"Johnson"<br style="word-wrap:break-word" />guile> (string? str)<br style="word-wrap:break-word" />#t<br style="word-wrap:break-word" />

    还可以用load过程来直接调用Scheme语言源文件并执行它,格式为:(load "filename"),还有read-char过程来读单个字符等等。

    输出

    常用的输出过程是display,还有write,它的格式是:(write 对象 端口),这里的对象是指字符串等常量或变量,端口是指输出端口或打开的文件。下面的操作过程演示了向输出文件temp中写入字符串"helloworld",并分行的实现。

    [root@toymouse test]# guile<br style="word-wrap:break-word" />guile> (define port1 (open-output-file "temp"))  ; 打开文件端口赋于port1<br style="word-wrap:break-word" />guile> port1<br style="word-wrap:break-word" />#<output: temp 3> <br style="word-wrap:break-word" />guile> (output-port? port1)<br style="word-wrap:break-word" />#t                     ; 此时证明port1为输出端口<br style="word-wrap:break-word" />guile> (write "hello\\nworld" port1)<br style="word-wrap:break-word" />guile> (close-output-port port1)<br style="word-wrap:break-word" />guile> (exit)               ; 写入数据并关闭退出<br style="word-wrap:break-word" />[root@toymouse test]# more temp          显示文件的内容,达到测试目的<br style="word-wrap:break-word" />"hello<br style="word-wrap:break-word" />world"<br style="word-wrap:break-word" />

    在输入输出操作方面,还有很多相关操作,读者可以参考R5RS的文档。







    五.语法扩展

    Scheme语言可以自己定义象cond,let等功能一样的宏关键字。标准的Scheme语言定义中用define-syntax和syntax-rules来定义,它的格式如下:

    		(define-syntax 宏名<br style="word-wrap:break-word" />			(syntax-rules()<br style="word-wrap:break-word" />				((模板) 操作))<br style="word-wrap:break-word" />				. . . ))<br style="word-wrap:break-word" />

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

    (define-syntax start<br style="word-wrap:break-word" />        (syntax-rules ()<br style="word-wrap:break-word" />                ((start exp1)<br style="word-wrap:break-word" />                        exp1)<br style="word-wrap:break-word" />                ((start exp1 exp2 ...)<br style="word-wrap:break-word" />                        (let ((temp exp1)) (start exp2 ...))) ))<br style="word-wrap:break-word" />

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

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


    在Scheme的规范当中,将表达式分为原始表达式和有源表达式,Scheme语言的标准定义中只有原始的if分支结构,其它均为有源型,即是用后来的宏定义成的,由此可见宏定义的重要性。







    六. 其它功能

    1. 模块扩展

    在R5RS 中并未对如何编写模块进行说明,在诸多的Scheme语言的实现当中,几乎无一例外的实现了模块的加载功能。所谓模块,实际就是一些变量、宏定义和已命名 的过程的集合,多数情况下它都绑定在一个Scheme语言的符号下(也就是名称)。在Guile中提供了基础的ice-9模块,其中包括POSIX系统调 用和网络操作、正则表达式、线程支持等等众多功能,此外还有著名的SFRI模块。引用模块用use-modules过程,它后面的参数指定了模块名和我们 要调用的功能名,如:(use-modules (ice-9 popen)),如此后,就可以应用popen这一系统调用了。如果你想要定义自己的模块,最好看看ice-9目录中的那些tcm文件,它们是最原始的定 义。

    另外Guile在面向对象编程方面,开发了GOOPS(Guile Object-Oriented Programming System),对于喜欢OO朋友可以研究一下它,从中可能会有新的发现。

    2. 如何输出漂亮的代码

    如何编写输出漂亮的Scheme语言代码应该是初学者的第一个问题,这在Guile中可以用ice-9扩展包中提供的pretty-print过程来实现,看下面的操作:

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

    3. 命令行参数的实现

    在把Scheme用做shell语言时,经常用到命令行参数的处理,下面是关于命令行参数的一种处理方法:

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

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

    [root@toymouse doc]# ./tz.scm abc 123 ghi<br style="word-wrap:break-word" />应用程序名称:./tz.scm<br style="word-wrap:break-word" />参数 1 是:abc<br style="word-wrap:break-word" />参数 2 是:123<br style="word-wrap:break-word" />参数 3 是:ghi<br style="word-wrap:break-word" />

    其中最主要的是用到了command-line过程,它的返回结果是命令参数的列表,列表的第一个成员是程序名称,其后为我们要的参数,定义loop递归调用形成读参数的循环,显示出参数值,达到我们要的结果。

    4. 特殊之处

    一些精确的自己计算自己的符号

    数字	Numbers		2 ==> 2<br style="word-wrap:break-word" />字符串	Strings		"hello" ==> "hello"<br style="word-wrap:break-word" />字符	Charactors	#\\g ==> #\\g<br style="word-wrap:break-word" />辑值    Booleans	#t ==> #t<br style="word-wrap:break-word" />量表	Vectors		#(a 2 5/2) ==> #(a 2 5/2)<br style="word-wrap:break-word" />

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

    如:

    	<br style="word-wrap:break-word" />	<br style="word-wrap:break-word" />	x ==> 9<br style="word-wrap:break-word" />	   -list ==> ("tom" "bob" "jim")<br style="word-wrap:break-word" />	factoral ==> #<procedure: factoral><br style="word-wrap:break-word" />		 ==> #<primitive: +><br style="word-wrap:break-word" />

    define 特殊的form

    (define x 9) ,define不是一个过程, 它是一个不用求所有参数值的特殊的form,它的操作步骤是,初始化空间,绑定符号x到此空间,然后初始此变量。

    必须记住的东西

    下面的这些定义、过程和宏等是必须记住的:

    define,lambda,let,lets,letrec,quote,set!,if,case,cond,begin,and,or等等,当然还有其它宏,必需学习,还有一些未介绍,可参考有关资料。

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

    展开全文
  • scheme简明教程

    2020-07-30 23:30:14
    这是一本在国外比较有名的Scheme编程语言的入门教材。本教材适合任何对Scheme编程语言感兴趣的人阅读,尤其是有其他编程语言(特别是动态语言)编程经验,希望快速了解Scheme的不同点并且快速上手写点东西的人。
  • Scheme

    千次阅读 2016-08-25 14:10:03
    Scheme是一种函数式编程语言,是Lisp的两种主要方言之一(另一种为Common Lisp)。不同于Common Lisp,Scheme遵循极简主义哲学,以一个小型语言核心作为标准,加上各种强力语言工具(语法糖)来扩展语言本身。麻省...
  • Scheme跳转协议

    千次阅读 2017-08-22 13:50:35
    URL Scheme协议Android中的Scheme是一种页面内跳转协议,通过自定义Scheme协议,可以跳转到app中的任何页面。 服务器可以定制化跳转app页面 app可以通过Scheme跳转到另一个app页面 可以通过h5页面跳转app原生页面 ...
  • Scheme定义 Scheme 编程语言是一种Lisp方言,诞生于1975年,由 MIT 的 Gerald J. Sussman 和 Guy L. Steele Jr. 完成。它是现代两大Lisp方言之一;另一个方言是Common Lisp。 Scheme遵循极简主义哲学,以一个小型...
  • 最美丽的编程语言Scheme——基本表达式

    万次阅读 热门讨论 2010-10-27 23:24:00
    Scheme被很多人誉为“世界上最美丽的编程语言”。偶也被他们的话所打动,于是乎开始了Scheme之旅。 目前Scheme大多用于科研,商用的比较少。但即便如此,也丝毫不会影像其“美丽”。 下面就请大家一起跟我走进...
  • xcode修改scheme名称

    万次阅读 2014-02-21 10:53:54
    针对修改完项目名称后scheme名称没有更改的问题 如图这两个名称不同,我要都改成PoketQHD 修改步骤如下 1、选择Manage schemes… 进入后 选择palmHI ->选择下面的设置按钮->选择duplicate  项目...
  • nginx如何使后端获取-scheme

    千次阅读 2013-12-12 10:31:53
    1、先上如何解决 在nginx的server配置中打上标记: nginx配置代码: proxy_set_header X-Http-scheme https;... private boolean isHttpsScheme(HttpServletRequest request) { Enumeration httpScheme =
  • 浏览器URL Scheme打开APP的那些坑

    万次阅读 2018-09-25 15:07:48
    URL Scheme打开APP网上有很多的具体实现,这里不重复了,只说说实际开发中遇到的坑。 1.应用A配置了scheme,应用B是可以通过url scheme直接打开应用A里配置了scheme的特定页面; 2.如果是浏览器用url scheme打开...
  • 错误代码:net::ERR_UNKNOWN_URL_SCHEME

    万次阅读 2018-04-24 11:11:11
    今天又个需求,通过tomcat...最后看控制台报错为net::ERR_UNKNOWN_URL_SCHEME.看了下我的路径为localhost:8080/maps/xx/xx/xx.png.最后找到的问题是没有加入"http://"这个头,因此访问不到.加上就正常咯~...
  • H5通过URL Scheme协议唤起App

    千次阅读 2020-10-21 09:26:01
    在 h5 页面上唤醒app ,需要用到 scheme协议(由app端提供),但是在微信浏览器里scheme不起作用,因此需要先判断是否为微信浏览器,是微信浏览器的话,提示到浏览器打开,不是的话,再判断是Android端还是iOS端,...
  • 几个免费的Scheme(Lisp)解释器

    万次阅读 2008-09-13 14:27:00
    几个免费的Scheme(Lisp)解释器 关键字: lisp scheme Lisp是一个古老的函数式编程语言,Scheme则起源于MIT的一种Lisp方言。当前编程语言的一些特性,如尾递归、匿名函数、动态改变代码的功能等等,不少是受到了...
  • 三种解决方式:1、 访问地址时需要有http:// 作为开头2、发送url时的转化问题,使用URL u = new URL(原url)转化3、ASCII装换问题。链接 http://blog.csdn.net/ismr_m/article/details/46383313...
  • java.net.URISyntaxException: Illegal character in scheme name at index 0: 原始写法: /* 实例化一个HttpClient客户端 */ /*HttpClient client = new DefaultHttpClient(); HttpGet getHttp =
  • 安卓app的webView加载网页后出现ERR_UNKNOWN_URL_SCHEME

    万次阅读 多人点赞 2018-05-29 14:06:40
    然在使用webView加载网页过程中,遇到了如上问题,显示ERR_UNKNOWN_URL_SCHEME 不知何故之下,学网上删去webView.setWebViewClient(new WebViewClient(){...},并加上webView.setWebChromeClient(new WebChromeC
  • -canOpenURL: failed for URL: "weixin://app/*************/" - error: "This app is not allowed to query for scheme weixin" iOS 9系统策略更新,限制了http协议的访问,此外应用需要在“Info.plist”中将要使用...
1 2 3 4 5 ... 20
收藏数 165,795
精华内容 66,318
关键字:

scheme