语法
最后更新于:2022-04-02 02:05:51
[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
```
';