输入输出
——chapter7 I/o
Teach Yourself Scheme in Fixnum Days
读取单个字符 :read-char
1 2 3 4 5 6 | > (read-char) f #\f > (read-char) #\newline > |
如上所示,输入(read-char)回车后,DrRacket会出来输入框,我输入f回车。
首先解释器会打出#\f,我再输入(read-char),则会输出回车。read-char每次只读取一个字符,若用户第一次输入多个字符,
则接着输入(read-char)时,自动会读取下面的字符,并进行输出。
读取一行字符:read-line
1 2 3 4 | > (read-line) kkkkkkkk "kkkkkkkk" > |
read-line返回的字符串并不包含换行符。
读取还有另一个过程read,不分字符还是字符串:
1 2 3 4 | > (read) dekdekdl 'dekdekdl > |
写单个字符:write-char
1 2 3 | > (write-char #\d) d > |
写字符串:wirte
1 2 3 | > (write "hello" ) "hello" > |
写过程默认输出在控制台。默认输入输出端口为current-input-port和current-output-port。
1 2 | (display 9 ) (display 9 (current-output-port)) |
上面两行语句结果相同。
文件输入输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | (define i (open-input-file "hello.txt" )) 定义输入文件,可用read-过程读取文件信息 (read-char i) 读取单个字符 (read-line i) 读取一行信息 (define o (open-output-file "hello1.txt" )) 定义写入文件,可以write-、display过程将信息写入文件 (display "hello" o) 将hello写入文件 "hello1.txt" (write-char #\space o) 将空格写入文件 (display 'qin o) 将字符qin写入文件 (newline o) 将换行符写入文件 (close-output-port o) 关闭文件 |
自动打开关闭文件过程:call-with-input-file、call-with-output-file
1 2 3 4 5 6 | (call- with -input-file "hello.txt" (lambda (i) (let* ((a (read-char i)) (b (read-char i)) (c (read-char i))) (list a b c)))) |
上面代码输出hello.txt的前三个字符。
1 2 3 4 5 6 7 8 9 | call- with -output-file在R5RS中 (call- with -output-file "hello1.txt" (lambda (p) (let f ((ls (list #\a #\b #\c))) ( if (not ( null ? ls)) (begin (write (car ls) p) (newline p) (f (cdr ls))))))) |
上面代码将(list #\a #\b #\c))写入文件hello1.txt
字符串的读取与写入
1 2 3 4 5 6 7 8 9 | open-input-string 在#lang racket中 (define i (open-input-string "hello world" )) (read-char i) (read i) (read i) 输出: #\h 'ello 'world |
read以空格为分界符,输出字符串的每一个单词。
1 2 3 4 5 6 | (define o (open-output-string)) 定义一个字符串输出对象 o (write 'hello o) (write-char #\, o) (display " " o) (display "world" o) |
读取字符串对象o的内容,使用get-output-string过程
(get-output-string o)
文件加载load & load-relative
chapter7.rkt文件为前面字符串输出对象及相关操作
1 2 3 4 5 6 7 | > (load "chapter7.rkt" ) > ( get -output-string o) "hello, world" > (load-relative "chapter7.rkt" ) > ( get -output-string o) "hello, world" > |
load-relative在MzScheme及racket中均有。
递归
——chapter6 Recursion
Teach Yourself Scheme in Fixnum Days
递归是个好东西,可以很清晰的刻画出程序流程来。
下面的递归程序是求斐波纳契亚数列。
1 2 3 4 | (define factorial (lambda (n) ( if (= n 0 ) 1 (* n (factorial (- n 1 )))))) |
而接下来的例子显示了递归互引用。
判断数字是否为偶数的is-even引用了判断是否为奇数的is-odd,两者交互引用。
1 2 3 4 5 6 7 8 | (define is -even? (lambda (n) ( if (= n 0 ) #t ( is -odd? (- n 1 ))))) (define is -odd? (lambda (n) ( if (= n 0 ) #f ( is -even? (- n 1 ))))) |
is-eve?和is-odd?也可以设置成局部过程,使用letrec关键字如下:
1 2 3 4 5 6 7 8 | (letrec ((local-even? (lambda (n) ( if (= n 0 ) #t (local-odd? (- n 1 ))))) (local-odd? (lambda (n) ( if (= n 0 ) #f (local-even? (- n 1 )))))) (list (local-even? 3 ) (local-odd? 3 ))) => (#f #t) |
等价语句块:
1 2 3 4 5 6 7 8 9 | (begin (define local-even? (lambda (n) ( if (= n 0 ) #t (local-odd? (- n 1 ))))) (define local-odd? (lambda (n) ( if (= n 0 ) #f (local-even? (- n 1 ))))) (list (local-even? 3 ) (local-odd? 3 ))) => (#f #t) |
用递归来表示循环
在scheme中,没有循环语句,只能通过递归俩表示循环。下面的代码循环输出10-1的数字:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | (letrec ((countdown (lambda (i) ( if (= i 0 ) "done" (begin (display i) (newline) (countdown (- i 1 ))))))) (countdown 10 )) (let countdown ((i 10 )) ( if (= i 0 ) "done" (begin (display i) (newline) (countdown (- i 1 ))))) |
上面两段代码结果相同:
1 2 3 4 5 6 7 8 9 10 11 | 10 9 8 7 6 5 4 3 2 1 "done" |
如上面两段代码所示,Scheme在实现循环的过程中使用了尾递归。
尾递归的另外一个例子:
1 2 3 4 5 6 7 8 9 | (define list-position (lambda (o l) (let loop ((i 0 ) (l l )) ( if ( null ? l) #f ( if (eqv? (car l) o) i (loop (+ i 1 ) (cdr l))))))) (define test-list (list #\a #\b #\c #\d)) (list-position #\c test-list) => 2 |
若o在list中存在,则该段代码返回list中的对象o的位置,否则返回#f。
1 2 3 4 5 6 7 8 9 | (define reverse! (lambda (s) (let loop ((s s) (r '())) ( if ( null ? s) r (let ((d (cdr s))) ( set -cdr! s r) (loop d s)))))) (reverse! (list #\a #\b #\c #\d)) => (#\d #\c #\b #\a) |
该段代码返回list列表逆序输出。但该段代码运行后,会改变list的内容。list最后返回值为逆序输出的最后一个值,上例中即为#\a。set-cdr!在R5RS中。
将过程在列表中遍历
主要通过两种方式,map和for-each。
1 2 | (map add2 '( 1 2 3 )) => ( 3 4 5 ) |
map将add2过程在列表上遍历,每个元素加2。
1 2 3 | > ( for - each display '( "one" "two" "three" )) onetwothree |
for-each将display过程在列表上遍历,打印每一个列表元素。
另外两个例子:
1 2 3 4 5 6 7 8 9 | > (map cons '(1 2 3) ' ( 10 20 30 )) (( 1 . 10 ) ( 2 . 20 ) ( 3 . 30 )) > (map + '(1 2 3) ' ( 10 20 30 )) ( 11 22 33 ) > (map + '(1 2 3) ' ( 10 20 30 ) '( 100 200 300 )) ( 111 222 333 ) > (map + '(1 2 3) ' ( 10 20 30 ) '( 100 200 )) . . mcar: expects argument of type <mutable-pair>; given () > |
map可以将过程加载在n个参数上,但每个参数形式应该一致。
map会在每一个参数列表上选取相应的元素,进行运算。
词法变量
——chapter5 Lexical variables
Teach Yourself Scheme in Fixnum Days
1 2 3 4 5 | (define x 9 ) (define add2 (lambda (x) ( set ! x (+ x 2 )) x)) |
1 2 3 4 5 6 7 8 9 10 | (define counter 0 ) (define bump-counter (lambda () ( set ! counter (+ counter 1 )) counter)) (add2 5 ) => 7 (bump-counter) => 1 (bump-counter) => 2 (bump-counter) => 3 counter => 3 |
1 2 3 4 5 | (define x 9 ) (let ((x 1 ) (y 2 ) (z 3 )) (list x y z)) => '( 1 2 3 ) |
1 2 3 | (let ((x 2 ) => x 定义为 2 (y x)) => y定义为x,该x为全局变量 (list x y)) => '( 2 9 ) |
1 2 3 | (let ((m 2 ) (y m)) (list m y)) |
1 2 3 | (let* ((x 2 ) (y x)) (list x y)) => '( 2 2 ) |
1 2 3 | (let ((x 1 )) (let ((y x)) => 该x即为外层let的x值 (+ x y))) => 2 |
1 2 | (let ((cons (lambda (x y) (+ x y)))) (cons 1 2 )) => 3 |
1 | (cons 1 2 ) => '( 1 . 2 ) |
1 2 3 4 | (fluid-let ((counter 99 )) (display (bump-counter)) (newline) => 100 (display (bump-counter)) (newline) => 101 (display (bump-counter)) (newline)) => 102 |
1 2 3 4 | (let ((counter 99 )) (display (bump-counter)) (newline) => 1 (display (bump-counter)) (newline) => 2 (display (bump-counter)) (newline)) => 3 |
上面let语句块中bump-counter读取的依然是全局变量中的counter值,而不是该语句块中的counter值。
条件语句
——chapter4 Conditionals
Teach Yourself Scheme in Fixnum Days
1 2 3 4 5 6 | > (define p 90 ) > ( if (> p 50 ) 'safe 'unsafe) safe > |
1 2 3 4 5 6 7 8 9 | (define p 5 ) (when (< p 4 ) (display p) ( set ! p (+ p 1 )) (newline)) (unless (< p 4 ) (display p) ( set ! p (+ p 1 )) (newline)) |
1 2 3 | ( if (< p 0 ) - 1 ( if (< p 5 ) 0 1 )) |
1 2 3 4 | (cond ((< p 0 ) - 1 ) ((< p 5 ) 0 ) ( else 1 )) |
1 2 3 4 5 6 | (define c #\b) ( case c ((#\a) 1 ) ((#\b) 2 ) ((#\c) 3 ) ( else 4 )) |
1 2 3 4 5 | > (and 2 '() 3 ) 3 > (and 2 '() 3 #f 9 ) #f > |
1 2 3 4 5 6 7 | > (or 1 2 ) 1 > (or #f 1 ) 1 > (or 3 #f) 3 > |
Forms
1 2 3 4 | > ( 1 . 2 ) . . procedure application: expected procedure, given: 1 ; arguments were: 0.2 > '( 1 . 2 ) ( 1 . 2 ) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | > ((lambda (x) (+ x 2 )) 3 ) 5 > (define add (lambda (x) (+ x 2 ) )) > (add 3 ) 5 > (define area (lambda (widh height) (* widh height))) > (area 2 4 ) 8 > (define area *) > (area 2 4 ) 8 > |
1 2 3 4 5 6 | > (define x '( 1 3 2 )) > (apply + x) 6 > (apply + 1 2 3 x) 12 > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | (define display3 (lambda (arg1 arg2 arg3) (begin (display arg1) (display " " ) (display arg2) (display " " ) (display arg3) (newline)))) (display3 1 2 3 ) (define display_3 (lambda (arg1 arg2 arg3) (display arg1) (display " " ) (display arg2) (display " " ) (display arg3) (newline))) (display_3 1 2 3 ) |
2.2 复合数据类型 & 2.3 & 2.4
——chapter2 Data types
Teach Yourself Scheme in Fixnum Days
1 2 3 4 5 | > "hello world" "hello world" > (string #\h #\e #\l #\l #\o) "hello" > |
1 2 3 4 5 6 | > (define greeting "hello;hello!" ) > (string-ref greeting 0 ) #\h > (string-ref greeting 3 ) #\l > |
1 2 | > (string-append "e " "pluribus" "Unum" "!" ) "e pluribusUnum!" |
1 2 3 4 5 6 7 8 9 | > (define a- 3 -char-long-string (make-string 3 )) > (string? a- 3 -char-long-string) #t > a- 3 -char-long-string "\u0000\u0000\u0000" > (string- set ! a- 3 -char-long-string 1 #\g) > a- 3 -char-long-string "\u0000g\u0000" > |
1 2 3 | > (string- set ! greeting 1 #\g) string- set !: expects type <mutable string> as 1st argument, given: "hello;hello!" ; other arguments were: 1 #\g > |
1 2 3 4 5 6 7 | > (vector 0 1 2 3 4 ) '#( 0 1 2 3 4 ) > (vector 'q ' b 'c) '#(q b c) > (vector (vector 1 2 3 ) (vector "h" "k" "m" )) '#(#( 1 2 3 ) #( "h" "k" "m" )) > |
1 2 3 4 5 6 7 8 9 10 11 | > (define v (make-vector 5 )) > (vector? v) #t > v '#( 0 0 0 0 0 ) > (vector-ref v 0 ) 0 > (vector- set ! v 2 8 ) > v '#( 0 0 8 0 0 ) > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | > (cons 1 #t) '( 1 . #t) > '( 1 . #f) '( 1 . #f) > ( 1 . #f) . application: bad syntax in : ( 1 . #f) > car #<procedure:car> > (car (cons 2 3 )) 2 > (define x (cons 4 #\g)) > (car x) 4 > (cdr x) #\g > |
1 2 3 4 | > ( set -car! x 2 ) reference to an identifier before its definition: set -car! > ( set -cdr! x #\j) reference to an identifier before its definition: set -cdr! |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | > (define y (cons (cons 1 2 ) 3 )) > y '(( 1 . 2 ) . 3 ) > (car (car y)) 1 > (caar y) 1 > (cdar y) 2 > (define z (cons (cons (cons 1 2 ) 3 ) 4 )) > (caaar z) 1 > (cdaar z) 2 > |
1 2 3 | > (cons 1 (cons 2 (cons 3 (cons 4 5 )))) '( 1 2 3 4 . 5 ) > |
1 2 3 4 5 | > (cons 1 (cons 2 (cons 3 (cons 4 ())))) . #%app: missing procedure expression; probably originally (), which is an illegal empty application in : (#%app) > (cons 1 (cons 2 (cons 3 (cons 4 '())))) '( 1 2 3 4 ) > |
1 2 3 | > (pair? '( 1 . 3 )) #t > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | > (list 1 2 3 4 ) '( 1 2 3 4 ) > '( 1 2 3 4 ) '( 1 2 3 4 ) > (define y (list 1 2 3 4 )) > (list-ref y 0 ) 1 > (list-ref y 3 ) 4 > (list-tail y 1 ) '( 2 3 4 ) > (list-tail y 3 ) '( 4 ) > (list? y) #t > |
1 2 3 | > ( null ? '()) #t > |
1 2 3 4 5 6 7 | > (char->integer #\d) 100 > (integer->char 50 ) #\ 2 > (string->list "hello" ) '(#\h #\e #\l #\l #\o) > |
1 2 3 4 5 6 7 | > (number->string 16 ) "16" > (string->number "16" ) 16 > (string->number "Am I a hot number?" ) #f > |
1 2 3 | > (string->number "16" 8 ) 14 > |
1 2 3 4 5 | > (symbol->string 'symbol) "symbol" > (string->symbol "string" ) 'string > |
1 2 3 | > (display "Hello, World!" (current-output-port)) Hello, World! > |
2.1 简单数据类型
——chapter2 Data types
Teach Yourself Scheme in Fixnum Days
1 2 3 4 5 6 7 8 9 10 11 | > (boolean? #t) #t > (boolean? "fd" ) #f > (not #f) #t > (not #t) #f > (not 't) #f > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | > (number? 42 ) #t > (number? #t) #f > (complex? 2 +3i) #t > (complex? 2 ) #t > (real? 3.21 ) #t > (real? 22 / 7 ) #t > (rational? 2 +3i) #f > (rational? 22 / 7 ) #t > (integer? 22 / 7 ) #f > (integer? 23 ) #t > |
1 2 3 4 5 6 7 8 9 | > #b1100 => 2 进制 12 > #o77 => 8 进制 63 > #d12 => 10 进制 12 > #x12 => 16 进制 18 > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | > (eqv? 42 42 ) #t > (eqv? 42 #f) #f > (eqv? 42 42.0 ) #f > (eqv? #b1100 #d12) #t > (eqv? #b1100 #x12) #f > (eqv? #b1100 #xd) #f > (eqv? #b1100 #xc) #t > |
1 2 3 4 5 | > (= 42 42 ) #t > (= 42 #f) =: expects type <number> as 2nd argument, given: #f; other arguments were: 42 > |
1 2 3 4 | > (= 42 42.0 ) #t > (eqv? 42 42.0 ) #f |
1 2 3 4 5 | > (< 4 't) <: expects type <real number> as 2nd argument, given: 't; other arguments were: 4 > (< 4 5.6 ) #t > |
1 2 3 4 5 6 7 8 9 | > (- 4 ) - 4 > (/ 4 ) 1 / 4 > (/ 0 ) /: division by zero > (- 0 ) 0 > |
1 2 3 4 5 6 7 | > (max 1 2 3 4 ) 4 > (min 1 2 3 4 ) 1 > (max #t 2 3 4 ) max: expects type <real number> as 1st argument, given: #t; other arguments were: 2 3 4 > |
1 2 3 | > (abs - 3.2 ) 3.2 > |
1 2 3 4 5 6 7 | > (char? #\c) #t > (char? 1 ) #f > (char? #\;) #t > |
1 2 3 4 5 6 7 8 9 10 11 | > (char<? #\a #\b) #t > (char>? #\a #\b) #f > (char=? #\a #\a) #t > (char=? #\a #\A) #f > (char>? #\a #\A) #t > |
1 2 3 | > (char-ci=? #\a #\A) #t > |
1 2 3 4 5 | > (char-downcase #\A) #\a > (char-upcase #\a) #\A > |
1 2 3 4 5 6 7 | > (eqv? (quote E) 'E) #t > (symbol? 'xyz) #t > (symbol? 42 ) #f > |
1 2 3 4 | > (eqv? (quote E) 'e) #f > (eqv? 'E ' e) #f |
1 2 3 | (define size 2 ) > size 2 |
1 2 3 4 | > ( set ! size "3" ) > size "3" > |
Hello world
chapter1 Enter scheme
——Teach Yourself Scheme in Fixnum Days
1 2 3 4 | ;the first program ( begin (display "hello,world!" ) (newline)) |
1 | (display "hello,world!" ) |
1 | (newline) |
1 2 3 | > "hello world!" hello world! > |