输入输出
——chapter7 I/o
Teach Yourself Scheme in Fixnum Days
读取单个字符 :read-char
> (read-char) f #\f > (read-char) #\newline >
如上所示,输入(read-char)回车后,DrRacket会出来输入框,我输入f回车。
首先解释器会打出#\f,我再输入(read-char),则会输出回车。read-char每次只读取一个字符,若用户第一次输入多个字符,
则接着输入(read-char)时,自动会读取下面的字符,并进行输出。
读取一行字符:read-line
> (read-line) kkkkkkkk "kkkkkkkk" >
read-line返回的字符串并不包含换行符。
读取还有另一个过程read,不分字符还是字符串:
> (read) dekdekdl 'dekdekdl >
写单个字符:write-char
> (write-char #\d) d >
写字符串:wirte
> (write "hello") "hello" >
写过程默认输出在控制台。默认输入输出端口为current-input-port和current-output-port。
(display 9) (display 9 (current-output-port))
上面两行语句结果相同。
文件输入输出
(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
(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的前三个字符。
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
字符串的读取与写入
open-input-string 在#lang racket中 (define i (open-input-string "hello world")) (read-char i) (read i) (read i) 输出: #\h 'ello 'world
read以空格为分界符,输出字符串的每一个单词。
(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文件为前面字符串输出对象及相关操作
> (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
递归是个好东西,可以很清晰的刻画出程序流程来。
下面的递归程序是求斐波纳契亚数列。
(define factorial (lambda (n) (if (= n 0) 1 (* n (factorial (- n 1))))))
而接下来的例子显示了递归互引用。
判断数字是否为偶数的is-even引用了判断是否为奇数的is-odd,两者交互引用。
(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关键字如下:
(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)
等价语句块:
(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的数字:
(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)))))
上面两段代码结果相同:
10 9 8 7 6 5 4 3 2 1 "done"
如上面两段代码所示,Scheme在实现循环的过程中使用了尾递归。
尾递归的另外一个例子:
(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。
(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。
(map add2 '(1 2 3)) => (3 4 5)
map将add2过程在列表上遍历,每个元素加2。
> (for-each display '("one" "two" "three")) onetwothree
for-each将display过程在列表上遍历,打印每一个列表元素。
另外两个例子:
> (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
(define x 9) (define add2 (lambda (x) (set! x (+ x 2)) x))
(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
(define x 9) (let ((x 1) (y 2) (z 3)) (list x y z)) => '(1 2 3)
(let ((x 2) => x 定义为2 (y x)) => y定义为x,该x为全局变量 (list x y)) => '(2 9)
(let ((m 2) (y m)) (list m y))
(let* ((x 2) (y x)) (list x y)) => '(2 2)
(let ((x 1)) (let ((y x)) => 该x即为外层let的x值 (+ x y))) => 2
(let ((cons (lambda (x y) (+ x y)))) (cons 1 2)) => 3
(cons 1 2) => '(1 . 2)
(fluid-let ((counter 99)) (display (bump-counter)) (newline) => 100 (display (bump-counter)) (newline) => 101 (display (bump-counter)) (newline)) => 102
(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
> (define p 90) > (if (> p 50) 'safe 'unsafe) safe >
(define p 5) (when (< p 4) (display p) (set! p (+ p 1)) (newline)) (unless (< p 4) (display p) (set! p (+ p 1)) (newline))
(if (< p 0) -1 (if (< p 5) 0 1))
(cond ((< p 0) -1) ((< p 5) 0) (else 1))
(define c #\b) (case c ((#\a) 1) ((#\b) 2) ((#\c) 3) (else 4))
> (and 2 '() 3) 3 > (and 2 '() 3 #f 9) #f >
> (or 1 2) 1 > (or #f 1) 1 > (or 3 #f) 3 >
Forms
> (1 .2) . . procedure application: expected procedure, given: 1; arguments were: 0.2 > '(1 . 2) (1 . 2)
> ((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 >
> (define x '(1 3 2 )) > (apply + x) 6 > (apply + 1 2 3 x) 12 >
(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
> "hello world" "hello world" > (string #\h #\e #\l #\l #\o) "hello" >
> (define greeting "hello;hello!") > (string-ref greeting 0) #\h > (string-ref greeting 3) #\l >
> (string-append "e " "pluribus" "Unum" "!" ) "e pluribusUnum!"
> (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" >
> (string-set! greeting 1 #\g) string-set!: expects type <mutable string> as 1st argument, given: "hello;hello!"; other arguments were: 1 #\g >
> (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")) >
> (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) >
> (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 >
> (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!
> (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 >
> (cons 1 (cons 2 (cons 3 (cons 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) >
> (pair? '(1 . 3)) #t >
> (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 >
> (null? '()) #t >
> (char->integer #\d) 100 > (integer->char 50) #\2 > (string->list "hello") '(#\h #\e #\l #\l #\o) >
> (number->string 16) "16" > (string->number "16") 16 > (string->number "Am I a hot number?") #f >
> (string->number "16" 8) 14 >
> (symbol->string 'symbol) "symbol" > (string->symbol "string") 'string >
> (display "Hello, World!" (current-output-port)) Hello, World! >
2.1 简单数据类型
——chapter2 Data types
Teach Yourself Scheme in Fixnum Days
> (boolean? #t) #t > (boolean? "fd") #f > (not #f) #t > (not #t) #f > (not 't) #f >
> (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 >
> #b1100 =>2进制 12 > #o77 =>8进制 63 > #d12 =>10进制 12 > #x12 =>16进制 18 >
> (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 >
> (= 42 42) #t > (= 42 #f) =: expects type <number> as 2nd argument, given: #f; other arguments were: 42 >
> (= 42 42.0) #t > (eqv? 42 42.0) #f
> (< 4 't) <: expects type <real number> as 2nd argument, given: 't; other arguments were: 4 > (< 4 5.6) #t >
> (- 4) -4 > (/ 4) 1/4 > (/ 0) /: division by zero > (- 0) 0 >
> (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 >
> (abs -3.2) 3.2 >
> (char? #\c) #t > (char? 1) #f > (char? #\;) #t >
> (char<? #\a #\b) #t > (char>? #\a #\b) #f > (char=? #\a #\a) #t > (char=? #\a #\A) #f > (char>? #\a #\A) #t >
> (char-ci=? #\a #\A) #t >
> (char-downcase #\A) #\a > (char-upcase #\a) #\A >
> (eqv? (quote E) 'E) #t > (symbol? 'xyz) #t > (symbol? 42) #f >
> (eqv? (quote E) 'e) #f > (eqv? 'E 'e) #f
(define size 2) > size 2
> (set! size "3") > size "3" >
Hello world
chapter1 Enter scheme
——Teach Yourself Scheme in Fixnum Days
;the first program (begin (display "hello,world!") (newline))
(display "hello,world!")
(newline)
>"hello world!" hello world! >