Схема передачи по ссылке

Как я могу передать переменную по ссылке в схеме?

Пример функциональности, которую я хочу:

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

(define y 2)

(foo y)

(display y) ;outputs: 5

Кроме того, есть ли способ вернуться по ссылке?


person Cam    schedule 16.07.2010    source источник


Ответы (7)


См. http://community.schemewiki.org/?scheme-faq-language вопрос. «Есть ли способ эмулировать вызов по ссылке?».

В общем, я думаю, что это борется с функциональной природой схемы, поэтому, возможно, есть лучший способ структурировать программу, чтобы сделать ее более похожей на схему.

person Jari    schedule 16.07.2010
comment
Хорошо, спасибо. Полезно знать, но похоже, что мне, вероятно, следует найти лучший способ сделать то, что я пытаюсь сделать :) - person Cam; 16.07.2010
comment
Это хороший справочник по эмуляции аргумента по ссылке с использованием блоков — и обратите внимание, что результат использования 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

person erjiang    schedule 16.07.2010

Вы можете использовать макрос:

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
person gcbenison    schedule 25.01.2012

лямбда!

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

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

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

(display y)(newline)
person grettke    schedule 16.07.2010
comment
это кажется другим, чем заданный вопрос (т.е. foo здесь принимает два аргумента, а не один) - person gcbenison; 25.01.2012

Яри ​​прав, передача по ссылке несколько нелогична, по крайней мере, с переменными. Однако поведение, которое вы хотите, используется и часто поощряется все время более схемным способом с использованием замыканий. Страницы 181 и 182(книги Google) в опытной схеме справляются лучше, чем я могу объяснить это.

Вот ссылка, которая дает макрос, который позволяет вам использовать c-подобный синтаксис для «передачи по ссылке». Сайт Олега — это золотая жила для интересного чтения, поэтому обязательно добавьте его в закладки, если вы еще этого не сделали.

http://okmij.org/ftp/Scheme/pointer-as-closure.txt

person Davorak    schedule 16.07.2010

Вы можете воздействовать на внешний контекст изнутри функции, определенной в этом внешнем контексте, что дает вам эффект передачи по ссылочным переменным, то есть функции с побочными эффектами.

(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.

person Community    schedule 29.10.2014

Вероятно, вы слишком много используете C, PHP или что-то в этом роде. В схеме вы не хотите делать такие вещи, как pass-by-*. Сначала поймите, что означает область действия и как ведут себя разные реализации (в частности, попытайтесь выяснить, в чем разница между LISP и Scheme).

По сути чисто функциональный язык программирования не имеет побочных эффектов. Следовательно, это означает, что передача по ссылке не является функциональной концепцией.

person mathk    schedule 16.07.2010