根据条件引用变量
Reference to a variable depending on a conditional
我们可以根据条件选择运算符:
(let ((x 10))
(display ((if (< 0 1) - +) x))
(newline)
)
; output -10
我们可以对变量做同样的事情吗?
(let ((x 0) (y 0))
(set! (if (< 0 1) x y) 1) ; evaluate a reference to a variable, not his value
(display x) (newline)
(display y) (newline)
)
如果条件为真,则设置 x
为 1,否则设置 y
为 1。
我的意思是不重复 set!
函数,我知道可以使用以下方法解决它:
(let ((x 0) (y 0))
(if (< 0 1)
(set! x 1)
(set! y 1)
)
(display x) (newline)
(display y) (newline)
)
目的是清理这段代码:
(define-macro (inc x n)
`(set! ,x (+ ,x ,n))
)
define hmap (make-hash-table 50))
(hashq-set! hmap 'foo "bar")
(hashq-set! hmap 'bar "foo")
(hashq-set! hmap 'baz 42)
(let ((n 0) (n-strings 0) (n-numbers 0))
(hash-fold
(lambda (key value seed)
(inc n 1)
(if (string? value)
(inc n-strings 1)
(if (number? value)
(inc n-numbers 1)
)
)
)
0 hmap
)
(format #t "The map contains ~a elements: ~a are strings and ~a are numbers\n"
n n-strings n-numbers
)
)
如何更优雅的实现?
可以这样读取变量,因为读取变量的结果只是一个普通的值。但是变量本身不是 first-class:你不能以仍然允许你写入它的方式存储 (if (< 0 1) x y)
的结果。
我认为你可以,但 set!
不会。我不确定下面的宏是否完全正确,但我认为它可能是。不过我只在 Racket 中测试过它。
(define-syntax st!
(syntax-rules (if cond)
[(_ (if test a b) v)
(if test
(st! a v)
(st! b v))]
[(_ (cond
[test a]
...) v)
(cond
[test (st! a v)]
...)]
[(_ var val)
(set! var val)]))
然后
> (let ((x 0) (y 0))
(st! (if (< 0 1) x y) 1)
(display x) (newline)
(display y) (newline))
1
0
请注意,你需要对所有你想让它进入的东西进行特殊处理,而且我对 syntax-rules
中的整个文字内容也有点不确定(我真的是穴居人 CL 人, 所以我只对用泥巴和碎饼干做的宏系统很满意。
我们可以根据条件选择运算符:
(let ((x 10))
(display ((if (< 0 1) - +) x))
(newline)
)
; output -10
我们可以对变量做同样的事情吗?
(let ((x 0) (y 0))
(set! (if (< 0 1) x y) 1) ; evaluate a reference to a variable, not his value
(display x) (newline)
(display y) (newline)
)
如果条件为真,则设置 x
为 1,否则设置 y
为 1。
我的意思是不重复 set!
函数,我知道可以使用以下方法解决它:
(let ((x 0) (y 0))
(if (< 0 1)
(set! x 1)
(set! y 1)
)
(display x) (newline)
(display y) (newline)
)
目的是清理这段代码:
(define-macro (inc x n)
`(set! ,x (+ ,x ,n))
)
define hmap (make-hash-table 50))
(hashq-set! hmap 'foo "bar")
(hashq-set! hmap 'bar "foo")
(hashq-set! hmap 'baz 42)
(let ((n 0) (n-strings 0) (n-numbers 0))
(hash-fold
(lambda (key value seed)
(inc n 1)
(if (string? value)
(inc n-strings 1)
(if (number? value)
(inc n-numbers 1)
)
)
)
0 hmap
)
(format #t "The map contains ~a elements: ~a are strings and ~a are numbers\n"
n n-strings n-numbers
)
)
如何更优雅的实现?
可以这样读取变量,因为读取变量的结果只是一个普通的值。但是变量本身不是 first-class:你不能以仍然允许你写入它的方式存储 (if (< 0 1) x y)
的结果。
我认为你可以,但 set!
不会。我不确定下面的宏是否完全正确,但我认为它可能是。不过我只在 Racket 中测试过它。
(define-syntax st!
(syntax-rules (if cond)
[(_ (if test a b) v)
(if test
(st! a v)
(st! b v))]
[(_ (cond
[test a]
...) v)
(cond
[test (st! a v)]
...)]
[(_ var val)
(set! var val)]))
然后
> (let ((x 0) (y 0))
(st! (if (< 0 1) x y) 1)
(display x) (newline)
(display y) (newline))
1
0
请注意,你需要对所有你想让它进入的东西进行特殊处理,而且我对 syntax-rules
中的整个文字内容也有点不确定(我真的是穴居人 CL 人, 所以我只对用泥巴和碎饼干做的宏系统很满意。