Scheme学习笔记
本文包括如下内容:
- 开发环境配置
- hello world
- 变量、过程
- 标准输入
- if语句
- 文件写入
环境
“工欲善其事 必先利其器”。
学习之前我们需要先将Scheme的运行环境搭建起来,环境分Win和Linux,在Win下,直接到 http://www.gnu.org/software/mit-scheme/ 下载,安装。
在Ubuntu下,使用apt-get安装(强制建议使用*inux环境),Scheme的解释器有多种选择,这里我们选择mzscheme和guile,二者都可。
; mzscheme安装 sudo apt-get install mzscheme ;guile 解释器安装 sudo apt-get install guile-1.8
Hello World
创建hello.scm文件,在编辑器(vi/emacs)中输入如下内容:
<span style="color: #808080; font-style: italic;">;hello.scm the first program</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">begin</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">display</span> <span style="color: #ff0000;">"hello world!"</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">newline</span><span style="color: #66cc66;">)</span><span style="color: #66cc66;">)</span>
在命令行下,guile hello.scm 或 mzscheme -r hello.scm
如果你直接使用guile或mzscheme命令进入其命令行模式。则可以通过(load “hello.scm”)加载执行,注意,这里的括号是必须的。
解释下这段代码:
在分号(;)之后一直到行末之间就是注释。如hello.scm的开头部分。标准的Scheme语言定义中没有多行注释,不过在它部分实现中还是存在的。比如在Guile中就有多行注释,以符号组合“#!”开始,以相反的另一符号组合“!#”结束,其中内容为注释。如果加了这样的注释,这个程序就只能用guile来运行,如果使用mzscheme命令来运行则会报错。如果考虑代码的通用性,不建议使用此类注释。
display是输出过程,将内容输出到屏幕, newline的作用是换行显示。
变量,过程
在scheme中变量是通过define关键字定义,通过set!改变,并且scheme的变量是固定的类型,这有些类似于现在的python, php等动态语言,其在运行过程中是可变的,或者说这些动态语言是从函数式编程语言中学习了这些特性。 scheme的过程定义也是通过define关键字来实现的,只是其格式与变量有一些不同。
结合上面的hello world示例,我们看一个示例:
<span style="color: #808080; font-style: italic;">;var.scm</span> <span style="color: #808080; font-style: italic;">; 定义变量x</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">define</span> x <span style="color: #cc66cc;">10</span><span style="color: #66cc66;">)</span> <span style="color: #808080; font-style: italic;">;定义过程cout</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">define</span> <span style="color: #66cc66;">(</span>cout x<span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">display</span> x<span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">newline</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">begin</span> <span style="color: #66cc66;">(</span>cout x<span style="color: #66cc66;">)</span> <span style="color: #808080; font-style: italic;">; 改变变量x的值, 这里没有改变类型</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">set!</span> x <span style="color: #cc66cc;">20</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span>cout x<span style="color: #66cc66;">)</span> <span style="color: #808080; font-style: italic;">; 改变变量x的值,这里将之前的整型换成了字符串</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">set!</span> x <span style="color: #ff0000;">"string test"</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span>cout x<span style="color: #66cc66;">)</span> <span style="color: #66cc66;">)</span>
定义过程除了上面示例中的方式外,还可以使用lambda来定义过程,其格式如下:
(define 过程名 ( lambda (参数 ...) (操作过程 ...)))
而我们的示例中的格式为:
(define (过程名 参数 ...) (操作过程 ...))
这两种方式都可以使用,如果你是需要使用匿名函数,使用lambda方案,去掉定义性内容,如下:
( lambda (参数 ...) (操作过程 ...))
标准输入
从标准输入读取字符串,这里只用到了read过程,如下示例:
; 标准输入 (begin (define str (read)) (display str) (newline) )
通过定义 str为从标准输入获取内容,即调用 read 获取,以换行或空格结束输入程序通过display过程打印输入的内容,调用newline换行输出。
if 语句
和我们常见的if语句结构一样,Scheme语言的if结构有两种格式,
- 一种格式为:(if 测试 过程1 过程2),对比PHP相当于if else,即测试条件成立则执行过程1,否则执行过程2。
- 另一种格式为:(if 测试 过程) ,对比PHP,相当于没有else语句的方式,即测试条件成立则执行过程,没有else情况发生。
此时,可能会想在PHP中还有elseif语句呢,那么在Scheme中是怎样的?在Scheme中没有else语句也没有相关结构,它是以另一外if语句实现,如果我们在PHP中,则其结构类似于:
<span style="color: #b1b100;">if</span> <span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span> <span style="color: #009900;">}</span><span style="color: #b1b100;">else</span> <span style="color: #009900;">{</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span> <span style="color: #666666; font-style: italic;">// if语句的嵌套,在Scheme只能此种方案,没有简化后的elseif</span> <span style="color: #009900;">}</span> <span style="color: #009900;">}</span>
例如下面代码:
<span style="color: #66cc66;">(</span><span style="color: #b1b100;">define</span> a <span style="color: #66cc66;">(</span><span style="color: #b1b100;">read</span><span style="color: #66cc66;">)</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">define</span> b <span style="color: #66cc66;">(</span><span style="color: #b1b100;">read</span><span style="color: #66cc66;">)</span><span style="color: #66cc66;">)</span> <span style="color: #808080; font-style: italic;">; 输出结果,包含从数字到字符串的转化</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">define</span> <span style="color: #66cc66;">(</span>display_rs x<span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">display</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">string-append</span> <span style="color: #66cc66;">(</span>number<span style="color: #66cc66;">-></span>string a<span style="color: #66cc66;">)</span> x <span style="color: #66cc66;">(</span>number<span style="color: #66cc66;">-></span>string b<span style="color: #66cc66;">)</span><span style="color: #66cc66;">)</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">if</span> <span style="color: #66cc66;">(</span><span style="color: #66cc66;"><</span> a b<span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span>display_rs <span style="color: #ff0000;">"<"</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">if</span> <span style="color: #66cc66;">(</span><span style="color: #66cc66;">=</span> a b<span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span>display_rs <span style="color: #ff0000;">"="</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span>display_rs <span style="color: #ff0000;">">"</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">)</span> <span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">newline</span><span style="color: #66cc66;">)</span>
示例程序从标准输入接收两个数字,a和b。对比两个数字,显示最终谁大谁小。 其中,string-append是字符串连接过程,number->string的作用是数字转化为字符串。 display_rs是一个自定义的过程,显示比较的结果用,其传入的值为比较后的结果。
文件写入:
<span style="color: #808080; font-style: italic;">;file.scm 文件操作</span> <span style="color: #808080; font-style: italic;">; 文件写入操作</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">define</span> port <span style="color: #66cc66;">(</span><span style="color: #b1b100;">open-output-file</span> <span style="color: #ff0000;">"temp"</span><span style="color: #66cc66;">)</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">if</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">output-port</span>? port<span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">begin</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">write</span> <span style="color: #ff0000;">"helloworld"</span> port<span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">close-output-port</span> port<span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">display</span> <span style="color: #ff0000;">"yes"</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">newline</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">begin</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">display</span> <span style="color: #ff0000;">"write file temp failed."</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">(</span><span style="color: #b1b100;">newline</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">)</span> <span style="color: #66cc66;">)</span>
在《Scheme 程序语言介绍之一》这篇文章的开头处有一段话,虽有些玩笑之言,却值得沉思:
在网上有这样一句有趣的评论:计算机科学的大部分,就是在重复发现很久以前别人就早已 发现过的东西。 当然,这是一句玩笑。不过我们可以给这句玩笑接个下巴:对于程序语言中 的每一个重要概念, 你都可以先在 Lisp 当中发明一次,再在 C++ 里面发明一次,再在 Java 里面发明一次, 再在 Python 里面发明一次,再在 Perl 里面发明一次,再在 Ruby 里面发明一次, 当然,最后还要在 C# 里面再发明一次。
在学习的过程中,参考了如下书籍和链接:
- 《The Scheme Programming Language》
- 《Structure and Interpretation of Computer Programs,Second Edition》
- http://zh.wikipedia.org/zh/Scheme
- http://www.ibm.com/developerworks/cn/linux/l-scheme/part2/
- http://www.ibm.com/developerworks/cn/linux/l-schm/index1.html
- http://www.ibm.com/developerworks/cn/linux/l-schm/index2.html
转载请注明:爱开源 » Scheme学习笔记一