title: Scheme入門
date: 2021-12-20 22:54:03
tags: lang
完全參考:
https://deathking.github.io/yast-cn/contents/chapter8.html
包括了到循環為止的語法
Installation
https://inst.eecs.berkeley.edu/~cs61a/fa14/assets/interpreter/scheme.html 在線的解釋器
sudo apt install mit-scheme
#進入scheme交互式界面
scheme
#^C then Q quit
編譯
將scheme代碼用vscode寫好以.scm后綴,如sum.scm
#open interface
scheme
#compile file
(cf "sum")
#import the module
(load "sum")
# import without compile
(load "hello.scm")
語法
基本設定(語言特殊)
一切都是函數。 包括語句。
(后面的標識符代表函數名。
所以一切都是list,確切地說S-表達式(atom或list)
expression
(- 10 3) → 7
(- 10 3 5) → 2
(* 2 3) → 6
(* 2 3 4) → 24
(/ 29 3) → 29/3
(/ 29 3 7) → 29/21
(/ 9 6) → 3/2
(exact->inexact (/ 29 3 7)) → 1.38095238095238
---
(quotient 7 3) → 2
(modulo 7 3) → 1
(sqrt 8) → 2.8284271247461903
;onerload
(atan 1) → 0.7853981633974483
(atan 1 0) → 1.5707963267948966
list
Lists are (beaded) cons cells with the cdr part of the last cons cell being '() .
. Cons cells are a memory spaces which storage two addresses. Cons cells can be made by function cons
Function cons allocates a memory space for two addresses as shown in Figure 1. and stores the address to 1 in one part and to 2 in the other part. The part storing the address to 1 is called car part and that storing the address to 2 is called cdr part.可以理解成兩個指針。
(The name cons
is an abbreviation of a English term 'construction' for your information.Car
and cdr
are abbreviations of Contents of the Address part of the Register and Contents of the Decrement part of the Register. )
(cons 1 2)
;Value 11: (1 . 2)
(cons 3 (cons 1 2))
;Value 15: (3 1 . 2) : (3 1 . 2) is a convenient notation for (3 . (1 . 2)).點和括號可以一起去掉
(cons 1 (cons 2 '()))
;Value: (1 2) : .'()可以去掉,形式上就變成了list,其實也符合“點和括號可以一起去掉”
(car '(1 2 3 4))
;Value: 1
(cdr '(1 2 3 4))
;Value 18: (2 3 4)
atom, special forms, quote, list(函數)
Data structures which do not use cons cells are called atom(對應基本數據類型). Numbers, characters, strings, vectors, and '()
are atom. '()
is an atom and a list as well.
Scheme has two kinds of operators: One is functions. Functions evaluate all the arguments to return value. The other is special forms. Special forms do not evaluate all the arguments. Besides quote
, lambda, define, if, set!, etc. are special forms.(不計算所有參數,懶求值?
quote is used to protect tokens from evaluation.As quote
is frequently used, it is abbreviated as '
. e.g.'(+ 2 3)
represents a list (+ 2 3)
itself.'+
represents a symbol +
itself.
Function list is available to make a list consisting of several elements. Function list
takes arbitrary numbers of arguments and returns a list of them.
define function 全局變量
The define is a operator to declare variables and takes two arguments. The operator declares to use the first argument as a global parameter and binds it to the second argument. 將第二個參數束定於作為全局變量的第一個參數
The lambda is a special form to define procedures. The lambda
takes more than one arguments and the first argument is the list of parameters that the procedure takes as arguments. As fhello
takes no argument, the list of the parameters is empty.
; Hello world as a variable
(define vhello "Hello world") ;1
; Hello world as a function
(define fhello (lambda () ;2
"Hello world"))
; hello with name
(define hello
(lambda (name)
(string-append "Hello " name "!")))
; sum of three numbers
(define sum3
(lambda (a b c)
(+ a b c)))
;shorten version,去掉lambda和括號, 把列表里的aug和函數名括起來
; hello with name
(define (hello name)
(string-append "Hello " name "!"))
; sum of three numbers
(define (sum3 a b c)
(+ a b c))
控制流
if
True is any value except false which is represented by #f. The representing value of true is #t. #f
and '()
are defined as the same object. (null? '())
is null?
(if predicate then_value else_value)
;sum of geometric progression
(define (sum-gp a0 r n)
(* a0
(if (= r 1)
n
(/ (- 1 (expt r n)) (- 1 r))))) ; !!
cond
(cond
(predicate_1 clauses_1)
(predicate_2 clauses_2)
......
(predicate_n clauses_n)
(else clauses_else))
(define (fee age)
(cond
((or (<= age 3) (>= age 65)) 0)
((<= 4 age 6) 0.5)
((<= 7 age 12) 1.0)
((<= 13 age 15) 1.5)
((<= 16 age 18) 1.8)
(else 2.0)))
布爾函數
Function not is available to negate predicates.
The and takes arbitrary number of arguments and evaluates them from left to right. It returns #f
if one of the arguments is #f
and the rest of arguments are not evaluated. On the other hand, if all arguments are not #f
, it returns the value of the last argument. 真時返回最后一個數。
The or takes arbitrary number of arguments and evaluates them from left to right. It returns the value of the first argument which is not #f
and the rest of arguments are not evaluated. It returns the value of the last argument if it is evaluated.感覺0 #f ’()混用。真時返回第一個真的數。
eq?It compares addresses of two objects and returns #t
if they are same.
eqv?It compares types and values of two object stored in the memory space.
equal?It is used to compare sequences such as list or string.
(define str "hello")
;Value: str
(eq? str str)
;Value: #t
;;; comparing numbers depends on implementations
(eq? 1 1)
;Value: #t
(eq? 1.0 1.0)
;Value: ()
(eqv? 1.0 1.0)
;Value: #t
(eqv? 1 1.0)
;Value: ()
;;; the following depends on implementations
(eqv? (lambda(x) x) (lambda (x) x))
;Value: ()
(equal? (list 1 2 3) (list 1 2 3))
;Value: #t
(equal? "hello" "hello")
;Value: #t
=, <, >, <=, >=These functions takes arbitrary number of arguments. If arguments are ordered properly indicated by the function name, the functions return #t
.
Functions char=?, char<?, char>?, char<=?, and char>=? are available to compare characters.
Functions char=?, char<?, char>?, char<=?, and char>=? are available to compare characters.
遞歸循環
(define (fact n)
(if (= n 1)
1
(* n (fact (- n 1)))))
(define (list*2 ls)
(if (null? ls)
'()
(cons (* 2 (car ls))
(list*2 (cdr ls)))))
;makes all list items twice
尾遞歸
tail recursive functions include the result as argument and returns it directory when the calculation finishes. 返回值作為參數
Especially, as Scheme specification requires conversion of a tail recursive to a loop, there is no function call overhead.
(define (fact-tail n)
(fact-rec n n))
(define (fact-rec n p)
(if (= n 1)
p
(let ((m (- n 1)))
(fact-rec m (* p m)))))
As fact-rec
does not wait the result of other functions, it disappears from the memory space when it finishes. 函數不在表達式中
let loop
The named let
is available to express loop. [code 3] shows a function fact-let
that calculates factorials using named let. The fact-let
uses a named let expression (loop), instead of fact-rec
shown in [code 2]. First it initializes parameters (n1, p) with n at the line marked with ; 1. These parameters are updated at the line marked with ; 2 after each cycle: Subtracting n1 by one and multiplying p by (n1-1)
A named let is a conventional way to express loops in Scheme.
(define (fact-let n)
(let loop((n1 n) (p n)) ; 1
(if (= n1 1)
p
(let ((m (- n1 1)))
(loop m (* p m)))))) ; 2
letrec
While it is similar to the named let
, a name defined by letrec
can refer itself in its definition. The letrec
syntax is used to define complicated recursive functions. [code 4] shows a letrec
version of fact
.
(define (fact-letrec n)
(letrec ((iter (lambda (n1 p)
(if (= n1 1)
p
(let ((m (- n1 1)))
(iter m (* p m))))))) ; *
(iter n n)))
do
Syntax do is available for repetition, even it is not used frequently. The format is like as follows:
(do binds (predicate value)
body)
[binds] → ((p1 i1 u1) (p2 i2 u2) ... )
(define (fact-do n)
(do ((n1 n (- n1 1)) (p n (* p (- n1 1)))) ((= n1 1) p)))
The variables n1 and p are initialized with n and n and subtracted by one and multiplying by (n1 - 1)
after each cycle, respectively. The function returns p when n1 becomes one.
I feel do
is rather complicated than named let
.
局部變量
local variables, which makes defining functions easier. Local variables can be defined using the let expression.
The let
expressions can be nested.
(let binds body)
[binds] → ((p1 v1) (p2 v2) ...)
(let ((i 1) (j 2))
(+ i j))
;Value: 3
(let ((i 1))
(let ((j (+ i 2)))
(* i j)))
;Value: 3
(let ((i 1) (j (+ i 2)))
(* i j))
;Error,As the scope of the variables is the body,
(let* ((i 1) (j (+ i 2)))
(* i j))
;Value: 3, let* expression is a syntax sugar of nested let expressions.
(define (quadric-equation a b c)
(if (zero? a)
'error ; 1
(let ((d (- (* b b) (* 4 a c)))) ; 2
(if (negative? d)
'() ; 3
(let ((e (/ b a -2))) ; 4
(if (zero? d)
(list e)
(let ((f (/ (sqrt d) a 2))) ; 5
(list (+ e f) (- e f)))))))))
Actually let
expression is a syntax sugar of lambda
expression: As the lambda
expressions is function definition, it makes a scope of variables.
(let ((p1 v1) (p2 v2) ...) exp1 exp2 ...)
⇒
((lambda (p1 p2 ...)
exp1 exp2 ...) v1 v2)
習題
隨堂練習
0 A function that takes three real numbers as arguments. It returns the product of these three numbers if at least one of them is negative.
(define (pro3or a b c)
(if (or (negative? a)
(negative? b)
(negative? c))
(* a b c)))
1 my-reverse
that reverse the order of list items. (Function reverse is pre-defined.)
2 Summarizing items of a list consisting of numbers.
3 Converting a string that represents a positive integer to the corresponding integer, i.e. "1232" → 1232. Input error check is not required.
Hint:Character to number conversion is done by subtracting 48 from the ASCII codes of characters #\0 ... #\9. Function char->integer
is available to get the ASCII code of a character.Function string->list
is available to convert string to a list of characters.
; 1
(define (my-reverse ls)
(my-reverse-rec ls ()))
(define (my-reverse-rec ls0 ls1)
(if (null? ls0)
ls1
(my-reverse-rec (cdr ls0) (cons (car ls0) ls1))))
;-------------------
; 2
(define (my-sum-tail ls)
(my-sum-rec ls 0))
(define (my-sum-rec ls n)
(if (null? ls)
n
(my-sum-rec (cdr ls) (+ n (car ls)))))
;--------------------
; 3
(define (my-string->integer str)
(char2int (string->list str) 0))
(define (char2int ls n)
(if (null? ls)
n
(char2int (cdr ls)
(+ (- (char->integer (car ls)) 48)
(* n 10)))))