Macros in scheme
Scheme 语言中的宏,一般我们会在各种编程语言中见到宏,在 Scheme 中也是同样的 idea
(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 负数)
避免重复的原因是,我们一次表达出了一个概念 (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) 来实现
(define (3-state
value
positive-body
zero-body
negative-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-state
100 (display "P") (display "Z") (display "N"))
; PZN
这种方式定义与调用会执行所有的 Scheme 语句,所以我们无法直接定义函数来实现。
因此我们需要定义宏 (macros),定义 syntax ,
(define-syntax
3-state
(syntax-rules ()
((3-state
value 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-state
100 (display "P") (display "Z") (display "N"))
; P
调用
> (3-state
0 (display "P") (display "Z") (display "N"))
; Z
> (3-state
-100 (display "P") (display "Z") (display "N"))
; N
在其他语言中如何实现
在 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
这是一部分 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')" );
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 x
return ret
three_state(3, pr("P"), pr("Z"), pr("N"))
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