Scheme 方案重新定义列表

Scheme 方案重新定义列表,scheme,blackjack,playing-cards,Scheme,Blackjack,Playing Cards,我有一个名为手牌的列表和另一个名为牌组的列表,这里的主要目标是在我调用fnction draw时,将列表牌组中的第一张牌(或元素)放入列表手牌中 > (draw hand deck) (2 C) > (draw hand deck) (2 C) (3 H) > (draw hand deck) (2 C) (3 H) (K D) 但每次我叫它手永远不会改变价值。。。 我不知道有没有像在O-Object中那样的方法可以永久更改手的内容 我最初定义手牌是空的,因为玩家没有牌可以

我有一个名为手牌的列表和另一个名为牌组的列表,这里的主要目标是在我调用fnction draw时,将列表牌组中的第一张牌(或元素)放入列表手牌中

> (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 '())

不能更改列表的内容,但可以更改名称所指的列表。因此:

(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”)”(“第一个”post”)和“(一个全新的列表)都是不可更改的(“不可变”)列表,但是一些列表的名称首先指向一个,然后指向另一个,然后指向第三个

警告:对于许多问题,您将希望避免设置!试着用不同的方式思考这个问题。例如,如果你在游戏中使用世界和宇宙,
然后,您将希望更新程序返回新的世界状态,而不是使用set!修改旧的。

哦,接下来您会发现,从调用函数的人的角度来看,更改函数中名称所指的列表不会更改该名称所指的内容。因此:

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

功能性解决方案,
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)

Vijay为方案提供了最佳解决方案。但是,如果您真的想通过永久更改列表来实现这一点,则需要使用
set car
设置cdr。这在Scheme中是不自然的,需要一些技巧才能实现:

首先定义手部
和甲板

(define hand '(dummy))
(define deck '((2 C) (3 H) (K D)))
hand
必须从现有元素开始,这样它就有一些现有的列表结构需要修改。您不能使用
设置汽车
设置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
是否为空