Как мога да предам променлива по референция в схема?
Пример за функционалността, която искам:
(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
Както каза 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
Можете да използвате макрос:
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
Jari е прав, че е малко безсхемно да се предава по референция, поне с променливи. Въпреки това поведението, което искате, се използва и често се насърчава през цялото време по по-подобен на схема начин чрез използване на затваряния. Страници 181 и 182(google books) в опитната схема вършат по-добра работа, отколкото мога да го обясня.
Ето препратка, която дава макрос, който ви позволява да използвате синтаксис, подобен на c, за „предаване по препратка“. Сайтът на Olegs е златна мина за интересни четива, така че не забравяйте да резервирате, отбележете го, ако още не сте го направили.
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)), (unbox x) и т.н., както е споменато в подкоментар от Eli, което е същото като решението за минуси, предложено от erjiang.
Вероятно сте използвали твърде много C, PHP или каквото и да било. В схемата не искате да правите неща като pass-by-*. Разберете първо какво означава обхват и как се държат различните реализации (по-специално опитайте се да разберете каква е разликата между LISP и Scheme).
По същество чисто функционалният език за програмиране няма страничен ефект. Следователно това означава, че преминаването по реф не е функционална концепция.