3

我想用一个函数同时改变两个常数,但不知何故它不起作用:

(define p 1)
(define q 1)

(define (change p q)
  (set! p (+ p 1))
  (set! q (+ q 1))) 
4

4 回答 4

2

这将起作用:

#lang racket
(define p 1)
(define q 1)

(define (increment-p-and-q)
  (set! p (+ p 1))
  (set! q (+ q 1)))


(display (list p q)) ; displays (1 1)
(newline)
(increment-p-and-q)  ; mutates p and q
(display (list p q)) ; displays (2 2)
(newline)

当您调用与全局变量具有相同绑定的过程时,它会被隐藏。如果您set!更改的是本地绑定,而不是全局绑定。

于 2013-09-25T21:19:15.697 回答
2

您可能正在使用一种没有隐式begin内部过程体的语言,所以让我们尝试显式地编写它:

(define p 1) ; declare variables as global, so they 
(define q 1) ; can be modified inside a procedure

(define (change-vars) ; don't pass them, they won't get modified inside proc
  (begin ; use begin to evaluate expressions sequentially from left to right
    (set! p (+ p 1))
    (set! q (+ q 1)))) ; value of last expression is returned, here's #<void>

它按预期工作:

p
=> 1
q
=> 1

(change-vars)

p
=> 2
q
=> 2
于 2013-09-26T00:58:12.057 回答
1

@Sylwester 对您的问题给出了一个很好的字面答案。另一个字面答案是,如果您希望函数改变其参数(将它们视为 C++ 中的引用参数),请使用boxes。例子:

(define (change p)
  (set-box! p (+ (unbox p) 1)))

(define p (box 1))

(for/list ([i 3])
  (change p)
  (unbox p))
; => '(2 3 4)

但是,在 Racket 中使用这样的突变并不常见或不鼓励。尽管您可以做到,但我们鼓励使用更实用的方法,甚至可以让 Racket 优化您的代码以更快地运行

于 2013-09-25T22:08:25.973 回答
1

您可以使用宏(在这种情况下定义语法规则),这样您就可以将变量作为参数传递:

#lang racket

(define p 1)
(define q 1)

(define-syntax-rule (change p q)
  (begin
    (set! p (+ p 1))
    (set! q (+ q 1))))

(display (list p q)) ; displays (1 1)
(newline)
(change p q)  ; mutates p and q
(display (list p q)) ; displays (2 2)
(newline) 
于 2013-09-27T14:17:05.363 回答