Как я могу передать переменную по ссылке в схеме?
Пример функциональности, которую я хочу:
(define foo
(lambda (&x)
(set! x 5)))
(define y 2)
(foo y)
(display y) ;outputs: 5
Кроме того, есть ли способ вернуться по ссылке?
Как я могу передать переменную по ссылке в схеме?
Пример функциональности, которую я хочу:
(define foo
(lambda (&x)
(set! x 5)))
(define y 2)
(foo y)
(display y) ;outputs: 5
Кроме того, есть ли способ вернуться по ссылке?
См. http://community.schemewiki.org/?scheme-faq-language вопрос. «Есть ли способ эмулировать вызов по ссылке?».
В общем, я думаю, что это борется с функциональной природой схемы, поэтому, возможно, есть лучший способ структурировать программу, чтобы сделать ее более похожей на схему.
box
, unbox
и set-box!
очень близок к использованию явного указателя в C. Кроме того, такое редко используется, но оно может быть полезным в некоторых случаях — Scheme поощряет функциональное программирование и не поощряет мутацию, но у нее нет фундаментальных возражений против этого. (Но в большинстве случаев вполне вероятно, что код новичка, делающий это, нуждается в некотором переосмыслении.)
- person Eli Barzilay; 16.07.2010
Как сказал Яри, обычно вы хотите избежать передачи по ссылке в Схеме, поскольку это предполагает, что вы злоупотребляете побочными эффектами.
Однако, если вы хотите, вы можете заключить все, что хотите передать по ссылке, в поле cons
.
(cons 5 (void))
создаст блок, содержащий 5. Если вы передадите этот блок процедуре, которая заменяет 5 на 6, ваш исходный блок также будет содержать 6. Конечно, вы должны помнить cons
и car
, когда это уместно.
В Chez Scheme (и, возможно, в других реализациях) есть процедура под названием box
(и ее компаньоны box?
и unbox
) специально для этой ерунды упаковки/распаковки: http://www.scheme.com/csug8/objects.html#./objects:s43
Вы можете использовать макрос:
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
лямбда!
(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
здесь принимает два аргумента, а не один)
- person gcbenison; 25.01.2012
Яри прав, передача по ссылке несколько нелогична, по крайней мере, с переменными. Однако поведение, которое вы хотите, используется и часто поощряется все время более схемным способом с использованием замыканий. Страницы 181 и 182(книги Google) в опытной схеме справляются лучше, чем я могу объяснить это.
Вот ссылка, которая дает макрос, который позволяет вам использовать c-подобный синтаксис для «передачи по ссылке». Сайт Олега — это золотая жила для интересного чтения, поэтому обязательно добавьте его в закладки, если вы еще этого не сделали.
http://okmij.org/ftp/Scheme/pointer-as-closure.txt
Вы можете воздействовать на внешний контекст изнутри функции, определенной в этом внешнем контексте, что дает вам эффект передачи по ссылочным переменным, то есть функции с побочными эффектами.
(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
Это решение ограничивает масштаб побочных эффектов.
В противном случае есть (определить x (поле 5)), (распаковать x) и т. д., как указано в подкомментарии Эли, что совпадает с решением против, предложенным erjiang.
Вероятно, вы слишком много используете C, PHP или что-то в этом роде. В схеме вы не хотите делать такие вещи, как pass-by-*. Сначала поймите, что означает область действия и как ведут себя разные реализации (в частности, попытайтесь выяснить, в чем разница между LISP и Scheme).
По сути чисто функциональный язык программирования не имеет побочных эффектов. Следовательно, это означает, что передача по ссылке не является функциональной концепцией.