Macros in scheme Scheme 语言中的宏,一般我们会在各种编程语言中见到宏,在 Scheme 中也是同样的 idea
I - 问题 (The problem) (define num 3); 定义符号 num 为 3(cond((zero? num) (display "Z"))((positive? num) (display "P"))(else (display "N")))设置一个条件判断,如果 num 为 0 ,则打印 Z (z 代表 zero 零),若为正数则打印 P (p 代表 positive 正数) , 其他则打印 N (n 代表 negative 负数)
II - 隐藏复杂度 (Hiding complexity) How can we avoid repeating ourselves? 如何避免重复,编程通用的方式是 DRY (don’t repeat yourself 不要重复你自己)How can we speak at the right level? 如何在一个高的层面 (in a high level) 使用 Scheme避免重复的原因是,我们一次表达出了一个概念 (express a concept),我们不需要在每次使用的时候都重新表达这个概念 (without re-express it every time),另一种原因是,我们不必要去思考底层实现 (implementation),转而去思考更高层面的问题。
仅用代码实现一次 (code your concept once),其他时候只需要引用 (refer to) 它,这里我们希望做的事是避免 (avoid) 重复代码中的条件表达式 (cond expression),do once and leave it alone.
在编程语言中 (In program languages), 有多种方式 (several way) 来实现
Functions 编写函数Classes 使用类Extending the language 扩展语言 Code generation 程序生成代码 (比如 Qt 扩展了 C++,并在编译时使用元对象系统生成 moc 相关的C++代码)Macros 宏 III - 初次尝试 (First attempt) (define (3-statevaluepositive-bodyzero-bodynegative-body)(cond((zero? value)zero-body)((positive? value)positive-body)(elsenegative-body)))我们定义一个函数 3-state 需要四个入参 value, positive-body, zero-body, negative-body 这个函数体是一个条件表达式 (cond expression)
尝试调用
(3-state100 (display "P") (display "Z") (display "N")); PZN这种方式定义与调用会执行所有的 Scheme 语句,所以我们无法直接定义函数来实现。
IV - 解决方案 (A solution)因此我们需要定义宏 (macros),定义 syntax ,
(define-syntax3-state(syntax-rules ()((3-statevalue positive-body zero-body negative-body)(cond((zero? value)zero-body)((positive? value)positive-body)(elsenegative-body)))))第二个参数为 syntax-rules ,这里是需要做的匹配和需要扩展的模板 (the matching you should do, the template you should expand), 使用模式匹配 (pattern),并使用内容替换 (substitute in code)
> (3-state100 (display "P") (display "Z") (display "N")); P调用
> (3-state0 (display "P") (display "Z") (display "N")); Z> (3-state-100 (display "P") (display "Z") (display "N")); N V - 其他的实现方式 (How else could we do this?)在其他语言中如何实现
5.1 - 宏 (Macros)在 C 中使用 Macros 举例如下
/* MACROS */#define THREESTATE(VALUE,PBODY,ZBODY,NBODY) \{\int v = (VALUE); \if (v == 0) { (ZBODY); }\else if (v > 0) { (PBODY); }\else { (NBODY); }\}int main(){THREESTATE(3, print("P\n"), print("Z\n"), print("N\n"));return 0;}macros 为 literal expression 无法调试 (debug), 如何在 scheme 中使用 substitute
5.2 - 引用 (Quoting)这是一部分 JavaScript 代码,函数体使用字符串来定义 (body express in strings),通过 eval 函数来调用。
function threeState( value, pbody, zbody, nbody ){if (value === 0) { eval( zbody ); }else if (value > 0) { eval( pbody ); }else { eval( nbody ); }}threeState(3, "print('P')", "print('Z')", "print('N')" ); 5.3 - 函数指针 (Function pointers) def three_state(value, p_body_fn, z_body_fn, n_body_fn):if value == 0: z_body_fn()elif value > 0: p_body_fn()else:n_body_fn()def pr( x ):def ret():print xreturn retthree_state(3, pr("P"), pr("Z"), pr("N")) 5.4 - 类 (class) class TestJava {interface IThreeStateBodies {void positiveBody();void zeroBody();void negativeBody();}static void threeState(int value, IThreeStateBodies bodies ) {if ( value == 0 ) bodies.zeroBody();else if ( value > 0 )bodies.positiveBody();elsebodies.negativeBody();}public static void main( String[] args ) {threeState( 3,new IThreeStateBodies() {public void positiveBody() {System.out.println( "P" );}public void zeroBody() {System.out.println( "Z" );}public void negativeBody() {System.out.println( "N" );}});}Java 通过定义 Interface