【问题标题】:Assigning variables in Scheme without using set在 Scheme 中分配变量而不使用 set
【发布时间】:2021-01-23 13:13:56
【问题描述】:

我正在尝试在我的方案程序中创建一个全局分数,并且对于我的函数的每次迭代,它要么增加 1,减少 1,要么不改变。例如,当我希望分数增加 1 时,我的函数中有这个:

(set! score (+ score 1)))

我可以使用 set 来做到这一点!但我需要一种不使用集合的方法来实现它!手术。任何帮助将不胜感激!

【问题讨论】:

  • 形成一个 state 数据结构,其中包含一个字段 score,并为函数的每次迭代创建一个新的 state。跨度>
  • 我不确定你所说的状态是什么意思。抱歉,我是 Scheme 新手
  • 状态是您需要跟踪的一切。因此,游戏将具有包含玩家位置、得分等的 GameState。在“游戏循环”中,您可以从前一个游戏状态创建一个新的游戏状态,从而避免改变全局变量的需要。

标签: scheme lisp racket r5rs


【解决方案1】:

诀窍是意识到你可以像这样替换:

(define (my-game ...)
  (let ([score 0])
    (some-kind-of-looping-construct
     ...
     (if <not-done>
         (begin
           (set! score <new-score-value>)
           (continue-loop))
         score))))

这样的:

(define (my-game ...)
  (define (loop ... score ...)
    ...
    (if <not-done>
        (loop ... <new-score-value> ...)
        score))
  (loop ... 0 ...))

特别是,您可以通过对重复绑定变量的某个函数的文本(但不是实际)递归调用来替换任何重复分配给某个变量的循环构造。

具体来说,让我们假设我们有一个看起来像这样的循环结构

(loop exit-fn form ...)

所以loop 是循环结构,exit-fn 是我们用来退出循环的魔法。

我假设有一些函数run-game-round 接受一个整数和当前分数,运行一轮游戏并返回新分数。

所以使用这个结构,我们可以编写某种游戏循环的骨架:

(let ((round 0)
      (score 0))
  (loop exit
    (set! score (run-game-round round score))
    (set! round (+ round 1))
    (cond
      [(> score 100)
       (exit 'win)]
      [(> round 100)
       (exit 'lose)])))

这是相当可怕的代码。

但我们可以将这段代码替换为:

(begin
  (define (run-game round score)
    (cond [(> score 100)
           'win]
          [(> round 100)
           'lose]
          [else
           (run-game (+ round 1)
                     (run-game-round round score))]))
  (run-game 0 0))

这段代码做的一模一样,但没有任何赋值。

【讨论】:

    【解决方案2】:

    没有set!:我们可以输入list或给定数量的args并使用函数递归。

    #lang racket
    (define (play-game game-round-lst)
      (local [(define (make-score s)
                (cond
                  [(equal? s 'win) 1]
                  [(equal? s 'drew) 0]
                  [(equal? s 'lose) -1]))]
        (apply + (map make-score game-round-lst))))
    
    ;;; TEST
    (play-game '(lose win drew lose win)) ; 0
    (play-game '(win lose drew win lose win lose)) ; 0
    
    

    在本地函数中使用set! 。 通过这种方法,您可以构建新游戏,而不必担心每个游戏中的丢失状态。

    #lang racket
    (define (make-game)
      (local [(define score 0)
              (define (setup-score n)
                (set! score (+ n score)))
              (define (service-manager msg)
                (cond
                  [(equal? msg 'win)
                   (setup-score 1)]
                  [(equal? msg 'drew)
                   (setup-score 0)]
                  [(equal? msg 'lose)
                   (setup-score -1)]
                  [(equal? msg 'show-score)
                   score]))]
        service-manager))
    
    ;;; TEST
    (define game1 (make-game))
    (define game2 (make-game))
    (game1 'win)
    (game2 'win)
    (game1 'drew)
    (game2 'drew)
    (game1 'lose)
    (game2 'lose)
    (game1 'show-score) ; 0
    (game2 'show-score) ; 0
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-24
      • 2013-04-17
      • 2021-08-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多