The Racket Guide阅读笔记,chapter 12, 14.
12 Pattern Matching
语法形式:
(match target-expr
[pattern expr ...+] ...)
pattern可以是
- 普通常量
- cons, list, vector的计算结果
- struct的构造函数
- 非引用,非构造函数的标识符在pattern里面会被当作变量用来绑定传入的参数(下划线_除外,它用来忽略绑定)
else在match里面不是关键字,可能会对cond以及case表达式造成困扰。
三点...
表示Kleen操作,在list或者vector模式里面会重复在前之前的元素。
> (match '(1 2 3 4)
[(list 1 x ... 4) x])
'(2 3)
> (match (list (hat 23 'bowler) (hat 22 'pork-pie))
[(list (hat sz styl) ...) (apply + sz)])
45
缩略号也可以嵌套。
准摘引也可以用来构建模式。更多的匹配形式可以参考racket/match
。例如match-let以及match-lambda。
13 Classes and Objects
略
14 Units (Components)
单元用于把程序组织成可编译和重用的单元。单元可以被调用。
14.1 Signatures and Units
单元接口通常按照签名来描述:
#lang racket
(define-signature toy-factory^
(build-toys ; (integer? -> (listof toy?))
repaint ; (toy? symbol? -> toy?)
toy? ; (any/c -> boolean?)
toy-color)) ; (toy? -> symbol?)
(provide toy-factory^)
接口的实现使用define-unit来进行:
#lang racket
(require "toy-factory-sig.rkt")
(define-unit simple-factory@
(import)
(export toy-factory^)
(printf "Factory started.\n")
(define-struct toy (color) #:transparent)
(define (build-toys n)
(for/list ([i (in-range n)])
(make-toy 'blue)))
(define (repaint t col)
(make-toy col)))
(provide simple-factory@)
14.2 Invoking Units
可以调用一个单元。但是要确保这个单元所需要的名字已经包含了。
因为simple-factory@
没有导入其他单元,所以可以直接调用
(invoke-unit simple-factory@)
上面的调用不会导入名字,如果需要导入名字到当前范围的话,需要:
(define-values/invoke-unit/infer simple-factory@)
然后就可以执行:
(define-values/invoke-unit/infer toy-store@)
需要确保相应的模块已经require了。
14.3 Linking Units
可以使用define-compound-unit/infer来链接多个单元:
> (require "toy-factory-sig.rkt")
> (require "toy-store-sig.rkt")
> (require "store-specific-factory-unit.rkt")
> (require "toy-store-unit.rkt")
> (define-compound-unit/infer toy-store+factory@
(import)
(export toy-factory^ toy-store^)
(link store-specific-factory@
toy-store@))
14.4 First-Class Units
define-unit的形式也可以改写成:
(define toy-store@
(unit
(import toy-factory^)
(export toy-store^)
(define inventory null)
(define (store-color) 'green)
....))
跟define-unit相比,这样做的一个问题是无法推断import和export。 因为define-unit会附加额外的信息。
但是好处是unit的定义可以出现在注入lambda的结构之中,例如:
(define toy-store@-maker
(lambda (the-color)
(unit
...
这种情况下,要使用define-values/invoke-unit
,而不是 define-values/invoke-unit/infer
来调用。同样的,导出的时候需要使用compound-unit
。
14.5 Whole-module Signatures and Units
racket/signature和racket/unit这两个模块名可以用来避免重复性的代码。
例如:
#lang racket/signature
build-toys ; (integer? -> (listof toy?))
repaint ; (toy? symbol? -> toy?)
toy? ; (any/c -> boolean?)
toy-color ; (toy? -> symbol?)
单元的前面toy-factory^是从文件名"toy-factory-sig.rkt"推断出来的。
14.6 Contracts for Units
14.6.1 Adding Contracts to Signatures
#lang racket
(define-signature contracted-toy-factory^
((contracted
[build-toys (-> integer? (listof toy?))]
[repaint (-> toy? symbol? toy?)]
[toy? (-> any/c boolean?)]
[toy-color (-> toy? symbol?)])))
(provide contracted-toy-factory^)
14.6.2 Adding Contracts to Units
(define-unit/contract wrapped-simple-factory@
(import)
(export (toy-factory^
[build-toys (-> integer? (listof toy?))]
[repaint (-> toy? symbol? toy?)]
[toy? (-> any/c boolean?)]
[toy-color (-> toy? symbol?)]))
...
14.7 unit versus module
从模块化的角度,unit使module更完备
- module更多用来管理全局命名空间。
- unit则用来给位接口提供某种实现。
(本篇完)