Scheme传递引用方式

11

我怎么在Scheme中通过引用传递一个变量?

以下是我想要的功能示例:

(define foo
  (lambda (&x)
    (set! x 5)))

(define y 2)

(foo y)

(display y) ;outputs: 5

另外,有没有一种方法可以通过引用返回值?

7个回答

12

请查看http://community.schemewiki.org/?scheme-faq-language中的问题“是否有一种模拟按引用传递的方法?”。

总的来说,我认为这与Scheme的函数式本质相抵触,因此可能有更好的方法来构建程序,使其更符合Scheme的风格。


很酷,谢谢。知道了,但看起来我应该想办法找到更好的方法来完成我想做的事情 :) - Cam
6
这是模拟“按引用传递参数”使用盒子的良好参考资料。请注意,使用boxunboxset-box!的结果与在C语言中使用显式指针非常接近。虽然很少使用这种方法,但在某些情况下它确实有用——Scheme鼓励函数式编程并阻止突变,但并不完全反对这样做。(但在大多数情况下,这样做的新手代码可能需要重新思考。) - Eli Barzilay

4
您可以使用宏:
scheme@(guile-user)> (define-macro (foo var)`(set! ,var 5))
scheme@(guile-user)> (define y 2)
scheme@(guile-user)> (foo y)
scheme@(guile-user)> (display y)(newline)
5

4

像Jari所说的那样,在Scheme中通常要避免传递引用,因为这表明你正在滥用副作用。

如果你想的话,可以将任何想要通过引用传递的内容封装在一个cons盒子中。

(cons 5 (void))

使用 cons 进行封装后,会生成一个包含数字 5 的盒子。如果将此盒子传递给更改数字 5 为 6 的过程,则原始盒子也将包含数字 6。当然,在适当的时候需要记得使用 conscar

在 Chez Scheme(以及其他一些实现)中,有一个称为 box(以及其伴随的 box?unbox)的过程,专门用于这种封箱/解箱问题:http://www.scheme.com/csug8/objects.html#./objects:s43


2

lambda!

(define (foo getx setx)
  (setx (+ (getx) 5)))

(define y 2)
(display y)(newline)

(foo
 (lambda () y)
 (lambda (val) (set! y val)))

(display y)(newline)

这似乎与问题所要求的不同(即此处的 foo 接受两个参数,而不是一个)。 - gcbenison

2

您可以从定义在外部上下文中的函数内部影响外部上下文,这使您具有按引用传递变量的影响,即具有副作用的函数。

(define (outer-function)
  (define referenced-var 0)
  (define (fun-affects-outer-context) (set! referenced-var 12) (void))
  ;...
  (fun-affects-outer-context)
  (display referenced-var)
)
(outer-function) ; displays 12

这个解决方案限制了副作用的范围。

否则,就像Eli在一个子评论中提到的那样,会出现(define x (box 5)), (unbox x)等问题,这与erjiang建议的cons解决方案相同。


2
Jari是正确的,使用引用传递变量有点不像Scheme。然而,您想要的行为通常以更类似于Scheme的方式使用闭包来实现,并且经常被鼓励。在经验丰富的Scheme中,第181页和182页(Google图书)对此进行了更好的解释。
这里有一个参考文献,提供了一种宏,允许您使用类似于C的语法进行“按引用传递”。如果您还没有收藏Oleg的网站,则他的网站是一个有趣阅读的宝库,请务必将其加入收藏夹。 http://okmij.org/ftp/Scheme/pointer-as-closure.txt

0

你可能已经使用了太多的C、PHP或其他编程语言。

在Scheme中,你不想做像传递-by-*这样的事情。

首先要理解作用域的含义以及不同实现的行为(特别是试图弄清楚LISP和Scheme之间的区别)。

本质上,纯函数式编程语言没有副作用。因此,传递-by-ref不是一个函数式概念。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接