[TOC] > [手册](https://deathking.github.io/yast-cn/contents/preface.html) ## 计算 ``` (- 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.380952380952381 //把分数转为浮点数 ``` ## quote引用 `(+ 2 3)`返回5,然而`(quote (+ 2 3))`则向程序返回`(+ 2 3)`本身。因为quote的使用频率很高,他被简写为’。 ``` ’(+ 2 3) 代表列表 (+ 2 3) 本身 `’+ 代表符号 + 本身; ``` ## 定义函数 ### 无参函数 (即全局变量) hello.rkt ``` ; Hello world as a variable (define vhello "Hello world") ;1 ; Hello world as a function (define fhello (lambda () ;2 "Hello world")) ``` `cmd`到文件所在目录,执行`racket` ``` (load "hello.rkt") vhello ;"Hello world" fhello ;Value 16: #[compound-procedure 16 fhello] (fhello) ;Value 17: "Hello world" ``` ### 有参函数 farg.skt ``` ; hello with name (define hello (lambda (name) (string-append "Hello " name "!"))) ; sum of three numbers (define sum3 (lambda (a b c) (+ a b c))) ``` 调用 ``` (load "farg.scm") (hello "Lucy") ;Value 20: "Hello Lucy!" (sum3 10 20 30) ;Value: 60 Hello ``` ### 一种函数定义的短形式 ``` ; hello with name (define (hello name) (string-append "Hello " name "!")) ; sum of three numbers (define (sum3 a b c) (+ a b c)) ``` ## 局部变量 ### let表达式 格式 变量的作用域(Scope)为`body`体 ``` (let binds body) [binds] → ((p1 v1) (p2 v2) ...) ``` demo ``` (let ([x 1] [y 2]) (+ x y)) ``` 嵌套 ``` (let ((i 1)) (let ((j (+ i 2))) (* i j))) ;Value: 3 ``` let*表达式可以用于引用定义在同一个绑定中的变量。实际上,let*只是嵌套的let表达式的语法糖而已。 ``` (let ((i 1) (j (+ i 2))) (* i j)) ;Error ;;;======== (let* ((i 1) (j (+ i 2))) (* i j)) ;Value: 3 ``` 实际上,let表达式只是lambda表达式的一个语法糖: ``` (let ((p1 v1) (p2 v2) ...) exp1 exp2 ...) ;⇒ ((lambda (p1 p2 ...) exp1 exp2 ...) v1 v2) ``` ## 重复 ### 递归 ``` (define (fact n) (if (= n 1) 1 (* n (fact (- n 1))))) ;;; (fact 5) => 5*4*3*2*1 ``` ### 尾递归 ``` (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))))) ;;; (fact-tail 5) ⇒ (fact-rec 5 5) ⇒ (fact-rec 4 20) ⇒ (fact-rec 3 60) ⇒ (fact-rec 2 120) ⇒ (fact-rec 1 120) ⇒ 120 ``` ## 高阶函数 ### 排序 高阶函数(Higher Order Function)是一种以函数为参数的函数。它们都被用于映射(mapping)、过滤 (filtering)、归档(folding)和排序(sorting)表 排序demo ``` ;;;常规排序 (sort '(7883 9099 6729 2828 7754 4179 5340 2644 2958 2239) <) ;⇒ (2239 2644 2828 2958 4179 5340 6729 7754 7883 9099) ;;; 按后两位进行排序 (sort '(7883 9099 6729 2828 7754 4179 5340 2644 2958 2239) (lambda (x y) (< (modulo x 100) (modulo y 100)))) ;⇒ (2828 6729 2239 5340 2644 7754 2958 4179 7883 9099) ``` ### map 格式:`(map procedure list1 list2 ...) ` ``` (map + '(1 2 3) '(4 5 6)) ;⇒ (5 7 9) (map (lambda (x) (* x x)) '(1 2 3)) ;⇒ (1 4 9) ``` ### for-each ``` for-each的格式与map一致。但for-each并不返回一个具体的值,只是用于副作用。 (define sum 0) (for-each (lambda (x) (set! sum (+ sum x))) '(1 2 3 4)) sum ;⇒ 10 ``` ### 过滤 ``` (keep-matching-items '(1 2 -3 -4 5) positive?) ;⇒ (1 2 5) ``` ### apply函数 将表展开,作为过程的参数 ``` (apply max '(1 3 2)) ;⇒ 3 (apply + 1 2 '(3 4 5)) ;⇒ 15 (apply - 100 '(5 12 17)) ;⇒ 66 ``` ## 输入输出 函数(open-input-file filename)可以用于打开一个文件 函数(read-char port)用于从端口中读取一个字符 当读取到文件结尾(EOF)时,此函数返回eof-object,你可以使用eof-object?来检查 函数(close-input-port port)用于关闭输入端口 ``` (define (read-file file-name) (let ((p (open-input-file file-name))) (let loop((ls1 '()) (c (read-char p))) (if (eof-object? c) (begin (close-input-port p) (list->string (reverse ls1))) (loop (cons c ls1) (read-char p)))))) ``` ``` (read-file "hello.txt") ``` ## 赋值 ### set! ``` (define var 1) ;赋值前参数应被定义 (set! var (* var 10)) var ; 10 ``` ### 赋值和内部状态 ``` (define bank-account (let ((balance 10)) (lambda (n) (set! balance (+ balance n)) balance))) ;balance 为body中操作,请查看let 的语法说明 ``` ``` (gates-bank-account 50) ;60 (gates-bank-account -55) ;5 ``` ### 表的破坏性操作(set-car!,set-cdr!) ``` (define tree '((1 2) (3 4 5) (6 7 8 9))) (set-car! (car tree) 100) ; ((100 2) (3 4 5) (6 7 8 9)) (set-cdr! (third tree) '(a b c)) ; ((100 2) (3 4 5) (6 a b c)) ``` ### 队列 ... ## 关联表和哈希表 ### 关联表 关联表是一个由序对组成的表,它是一个用于表达关联的基本数据类型。 如果它们找到序对的 **car** 等于给定的`key` 符号,字符,和数字常被作为键使用,因为它们可以使用诸如eq?或者eqv?的快速比较函数被比较。 在作为键被使用前,字符串应该被转换为符号,从而获得更好的性能 函数`assq`,`assv`,和`assoc` 函数都可进行搜索 ,分别使用 `eq?`,`eqv?`,和`equal?`进行比较 ``` (define wc '((hi . 3) (everybody . 5) (nice . 3) (to . 10) (meet . 4) (you . 8))) (assq 'hi wc) ;⇒ (hi . 3) (assq 'you wc) ;⇒ (you . 8) (assq 'i wc) ⇒ () (define n '((1 2 3) (4 5 6) (7 8 9))) (assv 1 n) ;⇒ (1 2 3) (assv 8 n) ;⇒ () ``` ### 哈希表 ``` (make-eq-hash-table size), (make-eqv-hash-table size), (make-equal-hash-table size), (make-string-hash-table size) ``` 分别使用eq?,eqv?,equal?,和string=?比较键的值 哈希表的初始大小(size)可以选择性指定(optional) ## 定义语法 (宏) 宏的写法与函数类似,但是犹豫函数的闭包性不能影响外部值. ``` (define-syntax add (syntax-rules () ((_ x) ;//_表示宏的名字 (set! x (+ x 1))))) ``` > 定义 `nil!` 宏.执行后把 定义的值复制为`'()` ``` (define a 2) (add a) a ;3 ``` ## 宏实现 while ``` (define-syntax while (syntax-rules () ((_ pred b1 ...) (let loop () (when pred b1 ... (loop)))))) ``` ``` (let ((i 0)) (while (< i 10) (display i) (display #\Space) (set! i (+ i 1)))) 0 1 2 3 4 5 6 7 8 9 ``` ### 多个定义模式 ``` (define-syntax incf (syntax-rules () ((_ x) (begin (set! x (+ x 1)) x)) ((_ x i) (begin (set! x (+ x i)) x)))) ``` ``` (let ((i 0) (j 0)) (incf i) (incf j 3) (display (list 'i '= i)) (newline) (display (list 'j '= j))) (i = 1) (j = 3) ``` ## error 错误处理 `error` 会中断程序 ``` (define demo ( (error "err") (print "hello") )) (print "word") //输出 //err ``` 案例:限制参数类型 ``` ;; checked-area-of-disk : scheme-value ->number ;; 如果 v 数的话,计算半径为 v 的圆盘的面积 (define (checked-area-of-disk v) (cond [(number? v) v] [else (error 'checked-area-of-disk "number expected")] )) (checked-area-of-disk "12") ; checked-area-of-disk: number expected ```