Схема за преминаване по препратка

Как мога да предам променлива по референция в схема?

Пример за функционалността, която искам:

(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

Както каза Jari, обикновено искате да избегнете преминаването по препратка в Scheme, тъй като предполага, че злоупотребявате със странични ефекти.

Ако искате обаче, можете да приложите всичко, което искате да предадете чрез препратка, в поле 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

Jari е прав, че е малко безсхемно да се предава по референция, поне с променливи. Въпреки това поведението, което искате, се използва и често се насърчава през цялото време по по-подобен на схема начин чрез използване на затваряния. Страници 181 и 182(google books) в опитната схема вършат по-добра работа, отколкото мога да го обясня.

Ето препратка, която дава макрос, който ви позволява да използвате синтаксис, подобен на c, за „предаване по препратка“. Сайтът на Olegs е златна мина за интересни четива, така че не забравяйте да резервирате, отбележете го, ако още не сте го направили.

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)), (unbox x) и т.н., както е споменато в подкоментар от Eli, което е същото като решението за минуси, предложено от erjiang.

person Community    schedule 29.10.2014

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

По същество чисто функционалният език за програмиране няма страничен ефект. Следователно това означава, че преминаването по реф не е функционална концепция.

person mathk    schedule 16.07.2010