Схема переопределения списка
У меня есть список, называемый рукой, и еще один, называемый колода, основная цель здесь состоит в том, чтобы взять первую карту (или элемент) в колоду списка и поместить ее в руку списка, когда я вызываю ничью fnction...
> (draw hand deck)
(2 C)
> (draw hand deck)
(2 C) (3 H)
> (draw hand deck)
(2 C) (3 H) (K D)
но каждый раз, когда я называю это, рука никогда не меняет значение... Я не знаю, есть ли способ, как в O-Object, постоянно менять содержание руки?
и я изначально определяю пустую руку, потому что у игрока нет карты для старта.
(define hand '())
4 ответа
Функциональное решение, с draw
отсутствие побочных эффектов:
;; Returns a cons whose car will be the new hand and cdr being the
;; rest of the original deck
(define (draw deck hand)
(if (not (null? deck))
(cons (cons (car deck) hand) (cdr deck))
(cons hand ())))
;; Gets the new hand from the cons returned by draw.
(define (hand cards) (car cards))
;; Gets the new deck from the cons returned by draw.
(define (deck cards) (cdr cards))
;; test
(define cards (draw '(1 2 3 4 5) ()))
cards
=> ((1) 2 3 4 5)
(hand cards)
=> (1)
(deck cards)
=> (2 3 4 5)
;; draw again
(set! cards (draw (deck cards) (hand cards)))
cards
=> ((2 1) 3 4 5)
(hand cards)
=> (2 1)
(deck cards)
=> (3 4 5)
Вы не можете изменить содержимое списка, но вы можете изменить список, к которому относится имя. Так:
(let ((some-list '("post")))
(display "initially: ")
(display some-list)
(newline)
(set! some-list (cons "first" some-list))
(display "added first: ")
(display some-list)
(newline)
(set! some-list '(a completely new list))
(display "finally: ")
(display some-list)
(newline)
some-list)
Теперь каждый из списков '("post") '("first" "post") и '(совершенно новый список) являются неизменяемыми ("неизменяемыми") списками, но имя some-list сначала указывает на один, затем на другой затем третий.
Предостережение: для многих проблем вам захочется избежать множества! и попытаться думать о проблеме по-другому. Например, если вы работаете с мирами и вселенными для своей игры, http://pre.plt-scheme.org/plt/doc/teachpack/2htdpuniverse.html вам нужно, чтобы ваши средства обновления возвращали новое состояние мира. вместо того, чтобы использовать набор! модифицировать старый.
О, и затем вы обнаружите, что изменение списка, на который ссылается имя внутри функции, не изменит того, на что ссылается имя, с точки зрения того, кто вызвал функцию. Так:
(define (foo lst)
(set! lst '(hi))
(display "within foo: ")
(display lst)
(newline)
lst)
(define my-list '(hello))
(foo my-list)
(display "after foo: ")
(display my-list)
(newline)
(set! my-list (foo my-list))
(display "using the result of foo: ")
(display my-list)
(newline)
Виджей имеет лучшее решение для Схемы. Однако, если вы действительно хотите сделать эту работу путем постоянного изменения списков, вам необходимо использовать set-car!
а также set-cdr!
, Это не естественно в Scheme, и для его работы требуется несколько хаков:
Сначала определите hand
а также deck
:
(define hand '(dummy))
(define deck '((2 C) (3 H) (K D)))
hand
должен начинаться с существующего элемента, чтобы иметь существующую структуру списка для изменения. Вы не можете использовать set-car!
а также set-cdr!
с ноль ('()
).
Теперь пиши draw
:
(define (draw from to)
; push the top element of `from` onto `to`
(set-cdr! to (copy to))
(set-car! to (car from))
; pop the top element of `from` off
(set-car! deck (cadr deck))
(set-cdr! deck (cddr deck)))
; also we need to define copy
(define (copy l)
(map (lambda (x) x) l))
Это означает, что последний элемент вашей руки всегда будет пустышкой. Было бы лучше добавить проверку для исходного случая и перезаписать его вместо нажатия:
(define (draw from to)
; push the top element of `from` onto `to` (just overwrite the first time)
(when (pair? (cdr to))
(set-cdr! to (copy to)))
(set-car! to (car from))
; pop the top element of `from` off
(set-car! deck (cadr deck))
(set-cdr! deck (cddr deck)))
Также вы должны проверить, что from
не пусто, прежде чем что-то делать.