【Scheme】Scheme 编程学习 (七) —— Macros 宏
文章目录
- I - 问题 (The problem)
- II - 隐藏复杂度 (Hiding complexity)
- III - 初次尝试 (First attempt)
- IV - 解决方案 (A solution)
- V - 其他的实现方式 (How else could we do this?)
- 5.1 - 宏 (Macros)
- 5.2 - 引用 (Quoting)
- 5.3 - 函数指针 (Function pointers)
- 5.4 - 类 (class)
原视频地址: https://www.bilibili.com/video/BV1Kt411R7Wf?p=7
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 宏
- Code generation 程序生成代码
III - 初次尝试 (First attempt)
(define (3-statevaluepositive-bodyzero-bodynegative-body)(cond((zero? value) zero-body)((positive? value) positive-body)(else negative-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)(else negative-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();else bodies.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