Reputation: 23
I'm having trouble changing the value of a passed in parameter. The set! function is only working on an already defined variable outside of the function. I want my function to change the values associated with the passed in parameters without the function returning anything. For example: I have the global variable deck1 and I want to make a function that adds the first element of the list to another list and then delete that element from the first list. Something like this:
(define deck1 (list 1 2 3 4 5))
(define hand1 (list 6 7))
(define (hit-card deck hand)
(set! hand (append hand (first deck)))
(set! deck (rest deck)))
If I ran the function on deck1 and hand1 (hit-card deck1 hand1)
, I want the result to be
deck1: 1 2 3 4 5 ==> 2 3 4 5
hand1: 6 7 ==> 6 7 1
Upvotes: 1
Views: 561
Reputation: 1409
I think what you want is call-by-reference, but Racket is call-by-value by default.
There are typically two ways to solve this problem in Racket.
#lang racket
(define deck1 (box (list 1 2 3 4 5)))
(define hand1 (box (list 6 7)) )
(define (hit-card deck hand)
(set-box! hand (cons (first (unbox deck)) (unbox hand)))
(set-box! deck (rest (unbox deck))))
(hit-card deck1 hand1)
(unbox deck1) ; => '(2 3 4 5)
(unbox hand1) ; => '(1 6 7)
#lang racket
(define-syntax-rule (define-get/put-id id get put!)
(define-syntax id
(make-set!-transformer
(lambda (stx)
(syntax-case stx (set!)
[id (identifier? (syntax id)) (syntax (get))]
[(set! id e) (syntax (put! e))])))))
(define-syntax-rule (define-cbr (id arg ...) body ...)
(begin
(define-syntax id
(syntax-rules ()
[(id actual (... ...))
(do-f (lambda () actual)
(... ...)
(lambda (v)
(set! actual v))
(... ...))]))
(define-for-cbr do-f (arg ...)
()
body ...)))
(define-syntax define-for-cbr
(syntax-rules ()
[(define-for-cbr do-f (id0 id ...)
(gens ...) body ...)
(define-for-cbr do-f (id ...)
(gens ... (id0 get put)) body ...)]
[(define-for-cbr do-f ()
((id get put) ...) body ...)
(define (do-f get ... put ...)
(define-get/put-id id get put) ...
body ...)]))
The program above created a new special form define-cbr
which something like define
in Racket but is call-by-reference.
(define deck1 (list 1 2 3 4 5))
(define hand1 (list 6 7))
(define-cbr (hit-card deck hand)
(set! hand (cons (first deck) hand))
(set! deck (rest deck)))
(hit-card deck1 hand1)
deck1 ; => '(2 3 4 5)
hand1 ; => '(1 6 7)
More details, see https://docs.racket-lang.org/guide/pattern-macros.html
Upvotes: 2
Reputation: 9252
You can't, and wanting to do this is almost always a sign of confusion: Racket is a mostly-functional language and wants you to write programs whose component parts are functions, not procedures with arbitrary side-effects. If the argument to the function is bound to a mutable object you can mutate that object. Lists (and more generally structures made out of conses) are not mutable in Racket normally.
Upvotes: 0