Scheme 简介
萧建木
2023-12-01
1、Lisp
两种主要方言(dialect):
Common Lisp:1991年完成的ANSI标准,统一了几种早期Lisp的理念,是可用于多种应用开发的大型环境,最为著名的应用是人工智能。
Scheme:产生于学术界,特意进行了精简化设计,经验证是一种很好的语言,既可用于计算机科学教学,又可以作为嵌入式脚本语言。
其它:小型的特定于应用的DSLs,如Emacs Lisp或AutoCAD的AutoLISP。
2、Scheme
Scheme是学院派的编程语言,实际应用主要有以下几个:
1)教学用途,例如,MIT SICP课程使用的语言
《Structure and Interpretation of Computer Programs (SICP)》经典
2)图像编辑软件GIMP使用Scheme作为脚本语言
3)GNOME桌面环境,作为脚本语言(用的是GNU Guile实现)
4)Google App Inventor for Android
Scheme语言的"极简"设计思想(Scheme 语言标准只有 50 页,C++ 1000多页)。
Scheme的编程思想有些已经渗透到其它编程语言中。
接触一些函数式的语言,可能会对实际工作中解决某些问题有所帮助。
【有一点对hacker们很重要,如果喜欢使用像Emacs这样的基于Lisp的编辑器的话,使用Scheme就可以与它进行交互或者是扩展它的功能了】
“和别人说起来自己会一点Scheme的话,那种感觉还是很棒的”
两个主要的产品:
Kawa(www.gnu.org/software/kawa)
SISC(www.sisc-scheme.org——the Second Interpreter of Scheme Code)
3、Kawa
是个框架,能创造可编译成Java字节码的新语言。
Scheme是其实现之一。
4、启动REPL(读取—求值—显示—循环)
java kawa.repl
该命令启动Kawa,并显示一个提示符:
#|kawa:1|#
REPL(Read-Eval-Print-Loop),是与运行中的Lisp系统进行交互的方式——它“Read”你的输入,进行“Eval”运算,“Print”计算结果,如此反复“Loop”。
开发Lisp程序的方式,与我们开发C/C++/Java/C#等程序时所遵循的“写代码、编译、运行”的周期不同。Lisp程序员需要,保持Lisp系统的运行状态,编译和运行时的界限模糊。
在REPL中,函数和变量在执行过程中都是可以修改的,代码也是动态解释和编译的。
在命令提示符后输入(exit),可退出Scheme命令行。
5、Scheme语法
例1,把两个数字加到一起。
#|kawa:1|# (+ 1 1)
2
Lisp表达式的典型结构或“格式”。
语法一致:表达式总被放在一对圆括号内,用前缀符号,“+”号放在两个参量前。
例2,格式嵌套,建立一个树状结构。
#|kawa:2|# (* (+ 1 1) (- 7 8))
-2
可在一行内写下所有的语句,可用缩进增加可读性。
Lisp代码的这种括号密集(parenthesis-heavy)型风格也称为“S表达式(s-expressions)”,可兼作定义结构化数据的通用方法。
语法简单,编写产生、修改代码的程序要比其它语言简单得多。
6、Scheme函数
例3,判断字符串长度,如果超过某值,结果为真,执行其后的表达式,输出提示信息。
#|kawa:3|# (if (> (string-length "Hello,world") 10)(display "True"))
True
Lisp有很多内建的函数,可以很方便的应用S表达式格式操纵数据。
Scheme的内建函数以同样的机理工作。
Scheme通常被看做是函数式程序设计语言大家庭中的一员。
与面向对象不同,Scheme抽象的主要手段是函数和它操纵的数据,而不是类和对象。
在这里所做的每一件事,实际上都是调用一些带有参数、能够返回运行结果的函数。
可以通过define关键字来自定义函数。
例4,定义一个add函数,接收a和b两个参数,函数体执行加法(+)计算后自动返回执行结果。
#|kawa:4|# (define (add a b) (+ a b))
#|kawa:5|# (add 1 1) ;定义了add函数后,在REPL中调用它
2
没有静态的类型声明,所有的类型检查都在运行时进行,与其它动态语言中的方式相同。
在Scheme的世界里,函数是一等公民,可以被传递。
例5,创建一个函数,接收一个参数,使其值翻番。
#|kawa:6|# (define (double a) (* a 2))
#|kawa:7|# (define numbers (list 1 2 4 8))
#|kawa:8|# (map double numbers)
(2 4 8 16)
list函数定义了一个包含三个数字的列表。
map函数:一个参数是个函数,另一个参数是列表(list)。map函数遍历列表中的每个元素,将其作为参数调用所提供的函数,最后将所得结果组成一个新列表(list)。这是实现for循环的函数化方法。