Scheme

命令行

  • 在终端执行mit-scheme打开scheme的命令行。

  • 编写test.scm文件,在命令行中加载:

    (load "test.scm")

表达式

基本使用

1 ]=>  (+ 1 2)

;Value: 3
  • 一对括号代表了一次计算的步骤,只输入+ 1 2会直接返回这三个元素;
  • 左括号后紧跟的是函数名,后面是参数;
  • 标记的分隔符是空格制表符或者换行符,逗号和分号不是分隔符;
  • 函数+可以接受任意多的参数。

四则运算

+-*/都接受任意数量的参数。函数exact->inexact 用于把分数转换为浮点数。由括号标记(token)以及分隔符组成的式子,称为S-表达式

(- 10 3 5)  				;Value: 2
(* 2 3)     				;Value: 6
(/ 29 3)    				;Value: 29/3
(exact->inexact(/ 29 3 7)) 	;Value: 1.380952380952381
(* (+ 2 3) (- 5 3)) 		;Value: 10

其他算术

(quotient 7 3) 	;Value: 2
(modulo 7 3)   	;Value: 1
(sqrt 8)       	;Value: 2.8284271247461903
(sin 1)			;Value: .8414709848078965
(expt 2 5)		;Value: 32

生成表

Cons单元

Cons单元(Cons cells)是一个存放了两个地址的内存空间,可用函数cons生成。

(cons 1 2)		;Value: (1 . 2)

函数cons给两个地址分配了内存空间,存放指向1的地址的内存空间被称作car部分,存放指向2的地址的内存空间被称作cdr部分。

(cons 3 (cons 1 2))		;Value: (3 1 . 2)

其内存空间如下图:

其他例子如下:

(cons (cons 1 2) 3)				;Value: ((1 . 2) . 3)
(cons #\a (cons 3 "hello"))		;Value: (#\a 3 . "hello")

表是Cons单元通过用cdr部分连接到下一个Cons单元的开头实现的。表中包含的’()被称作空表。就算数据仅由一个Cons单元组成,只要它的cdr单元是’(),那它就是一个表。

原子

不使用Cons单元的数据结构称为原子(atom)。数字、字符、字符串、向量和空表’()都是原子。’()既是原子,又是表。

引用

所有记号都会从最内层的括号依次向外层括号求值,最外层括号返回的值将作为S-表达式的值。引用(quote)可以用来阻止记号被求值,quote简写为',比如’(+ 2 3)代表列表(+ 2 3)本身,空表'()前面的'也是引用。

(+ 2 3)				;Value: 5
(quote(+ 2 3))		;Value: (+ 2 3)
'(+ 2 3)			;Value: (+ 2 3)
'+					;Value: +

car和cdr函数

carcdr函数会返回一个Cons单元的car部分和cdr部分。

(car '(1 2 3 4))		;Value: 1
(cdr '(1 2 3 4))		;Value: (2 3 4)

list函数

用于构建表,可以有任意个参数。

(list)				;Value: ()
(list 1 2)			;Value: (1 2)
(list '(1 2) 3)		;Value: ((1 2) 3)

函数

define

define用于声明变量,它接受两个参数。define会使用第一个参数作为全局参数,并将其与第二个参数绑定起来。

(define vhello "Hello world")				;绑定字符
(define fhello (lambda () "Hello world"))	;绑定过程
vhello		;Value: "Hello world"
fhello		;Value: #[compound-procedure 17 fhello]
(fhello)	;Value: "Hello world"

lambda

lambda用于定义过程,其第一个参数是过程所需的参数列表。

(define hello
    (lambda (name)
        (string-append "Hello " name "!")))

(define sum3
    (lambda (a b c)
        (+ a b c)))
(hello "Lucy")		;Value: "Hello Lucy!"
(sum3 10 20 30)		;Value: 60

或者使用如下简写:

(define (hello name)
    (string-append "Hello " name "!"))

(define (sum3 a b c)
    (+ a b c))

分支

if

格式如下:

(if predicate then_value else_value)

如果predicate部分为真,那么then_value部分被求值,否则else_value部分被求值,并且求得的值会返回给if语句的括号外。true是除false以外的任意值,true使用#t表示,false#f表示。

可以省去else_value项,这样的话,当predicate为假时,返回值就没有被指定。如果希望当predicate为假时返回#f,那么就要明确地写出来。

(define (myabs x y)
    (if (> x y)
        (- x y)
        (- y x)
    )
)

函数null?用来判断表是否为空。

(null? '())		;Value: #t

函数not可用于对谓词取反。

(not #t)		;Value: #f

cond

用于处理多个条件的情况,格式如下:

(cond
  (predicate_1 clauses_1)
  (predicate_2 clauses_2)
    ......
  (predicate_n clauses_n)
  (else        clauses_else))

cond表达式中,predicates_i按照从上到下的顺序求值,而当predicates_i为真时,clause_i会被求值并返回。i之后的predicatesclauses不会被求值。如果所有的predicates_i都是假的话,则返回cluase_else

(define (score n)
    (cond
        ((>= n 80) 'A)
        ((<= 60 n 79) 'B)
        ((<= 40 n 59) 'C)
        (else 'D)
    )
)

eq?、eqv?和equal?

  • eq?:比较两个对象的地址,如果相同的话就返回#t
  • eqv?:比较两个存储在内存中的对象的类型和值,如果类型和值都一致的话就返回#t;
  • equal?:用于比较表或者字符串一类的序列。

用于比较数的函数

=><<=>=都有任意个数的参数。

局部变量

let表达式是lambda表达式的一个语法糖。格式如下:

(let binds body)

binds中声明的变量可以在body里使用。

(let ((i 1) (j 2))
      (+ i j))
;Value: 3

递归

函数式程序中没有循环,循环是通过递归实现的。

尾递归是指递归调用发生在函数的最后一个语句中。这样函数调用就无需保存多个栈帧,当计算结束时直接将其返回。(Scheme规范要求尾递归调用转化为循环,因此尾递归调用就不存在函数调用开销)

;判断元素是否在列表中
(define (member atm lis)
    (cond
        ((null? lis) #f)
        ((eq? atm (car lis)) #t)
        (else (member atm (cdr lis)))
    )
)
;求两个列表的交集
(define (guess lis1 lis2)
    (cond
        ((null? lis1) '())
        ((member (car lis1) lis2)
            (cons (car lis1) (guess (cdr lis1) lis2)))
        (else (guess (cdr lis1) lis2))
    )
)

高阶函数

高阶函数(Higher Order Function)是一种以函数为参数的函数。

map

(map procedure list1 list2 ...)

mapprocedure应用于列表中的每个元素,返回一个包含结果的新列表。procedure是与某个过程或lambda表达式相绑定的符号,参数表的个数视procedure需要的参数而定。

(map + '(1 2 3) '(4 5 6))			;Value: (5 7 9)
(map (lambda (x) (* x x)) '(1 2 3))	;Value: (1 4 9)

filter

filter 函数接受一个谓词函数和一个列表,返回满足谓词函数条件的元素的新列表。

(filter (lambda (x) (> x 2)) '(1 2 3 4 5))
;Value: (3 4 5)

reduce

(reduce procedure init list)

reduce是一个将列表元素通过某个操作归约为单一结果的函数。

(reduce + 0 '(1 2 3 4)) 						;Value: 10
(reduce (lambda (x y) (* x y)) 1 '(1 2 3 4))	;Value: 24

sort

(sort '(3 5 1 4 -1) <)		;Value: (-1 1 3 4 5)

Scheme
https://shuusui.site/blog/2024/12/22/scheme/
作者
Shuusui
发布于
2024年12月22日
更新于
2024年12月22日
许可协议