在某些lisp语言上,这种Python散列写入/访问代码的等价物是什么?

在某些lisp语言上,这种Python散列写入/访问代码的等价物是什么?,python,data-structures,clojure,lisp,scheme,Python,Data Structures,Clojure,Lisp,Scheme,这段Python代码的等价物是什么: class Player: def __init__(self): self.hp = 10 self.pos = [0,0,0] self.items = [] def damage(self,dmg): self.hp -= dmg player = Player() player.damage(3) player.pos[0] += 5 player.items.app

这段Python代码的等价物是什么:

class Player:
    def __init__(self): 
        self.hp = 10
        self.pos = [0,0,0]
        self.items = []
    def damage(self,dmg):
        self.hp -= dmg

player = Player()
player.damage(3)
player.pos[0] += 5
player.items.append("banana")

print player.hp, player.pos, player.items
>> 3 [5,0,0] ["banana"]
在Clojure(或其他Lisp)中?

在Clojure中:

(def player {
    :hp 10
    :pos [0 0 0]
    :items [] })

(defn damage [player amount]
    (update-in player [:hp] - amount))

(defn move [player direction]
    (update-in player [:pos] #(map + % direction)))

(defn give [player item]
    (update-in player [:items] conj item))

(-> player
    (damage 3)
    (move [5 0 0])
    (give "banana"))

; Output: {:hp 7, :pos (5 0 0), :items ["banana"]}

在Clojure中,您通常不会使用可变数据结构,而是创建一段描述播放器当前状态的不可变数据。对播放器的更新将创建一段描述更新状态的新数据。马特的回答给出了一个很好的例子

如果你想在一段时间内保持一个“玩家”身份,并多次改变状态,你可以用一个atom来实现,如下所示:

(def initial-player-state 
 {:hp 10
  :pos [0 0 0]
  :items []})

(def player (atom initial-player-state))

;; Define some update functions

(defn damage [player dmg]
  (update-in player [:hp] + dmg))

(defn move [player dir]
  (update-in player [:pos] #(vec (map + % dir))))

(defn add-item [player item]
  (update-in player [:items] conj item))

;;  Make some changes

(swap! player move [5 0 0])
(swap! player damage -3)
(swap! player add-item "Apple")

;; view the current player state by dereferencing the atom

@player
=> {:hp 10, :pos [0 0 0], :items ["Apple"]}
请注意,在真实的游戏中,您可能在单个原子中拥有整个不可变的游戏状态,而不仅仅是玩家。

在:

如果使用Racket,您可能希望以更实用的方式编程,在这种情况下,您可以编写如下方法以避免变异:

(define/public (damage dmg)
  (new this% [hp (- hp dmg)] [pos pos] [items items]))
在公共Lisp中:

(defclass播放器()
((hp:accessor hp:initform 10)
(pos:accessor pos:initform(列表0))
(项:访问器项:initform nil)))
(解除方法伤害((a玩家)伤害)
(decf(hp a-player)伤害)
在REPL中

;编译(DEFCLASS播放器…)
; 编译(消除方法损坏…)
CL-USER>(defparameter*player*(生成实例“player”)
*玩家*
CL-USER>(伤害*玩家*3)
7.
CL-USER>(incf(汽车(pos*player*)5)
5.
CL-USER>(推送:香蕉(物品*玩家*)
(:香蕉)
CL-USER>(列表(hp*播放器*)(pos*播放器*)(项目*播放器*)
(7(50)(香蕉))
CL-USER>

就我个人而言,我会将
pos
分解为单独的
x
y
z
,并可能定义一些方法来将东西放入和取出库存,以防我以后决定更改表示形式。

不,我只是想看看Lisp如何处理这个问题。我试过:读了一些实用CL的章节;这看起来太复杂了,或者说,如果是一样的话,我也会变得越来越复杂。在Clojure上,我不明白他在用结构映射做什么,后来又在用分派函数做什么。我不确定在这种情况下会使用哪一个(或其他特性),因此,我为什么要问这个问题。几乎任何一种语言都有小的例子,而你的问题都找不到1比1,它可能会告诉你方法感谢你指出错误;我没有测试代码,因为它只是一个概念性的示例,数字不是重点。不过,我认为你错过了否决投票的动机。否决投票有很多原因,比如它不是一个真正的问题。但是作者缺乏努力(如果是这样的话)并不是一个很好的理由,因为这个问题仍然可以帮助许多有同样疑问的人。咨询过去答案的人比问新问题的人多得多。@Dokkat如果你想报答你的帮助,那很容易——只要接受其中一个答案“我总是接受答案”。。。对于“永远”的一些定义,特别是61%的时间。谢谢你,但我无意中否决了你的答案。堆栈溢出不允许我更改它:@Dokkat,我编辑了答案,只是为了让你修复意外的否决票。(我所做的只是在末尾加了一个空行。)回答得好,谢谢!我可能会将位置表示为(向量0),并仔细研究是否有一个共享的列表,或者为每个调用获取新列表。我可能会将初始值保留为零,并创建一个播放器创建函数。谢谢,回答得很好。我现在得到原子概念。@只得到原子的当前值(状态),即播放器哈希映射。如果你只做
player
,你会得到原子本身,而不是原子的内容……非常简单,谢谢!我可以为(assoc player:attr(conj(player:attr)项))编写一个宏吗?我已经编辑了我的答案,以便在中使用
update,我认为这在本例中更为惯用,同时也减少了对宏的需要。当然,我们可以编写一个宏来进一步缩短时间。(但在这种情况下,我认为没有必要这样做,甚至可能会影响可读性)
(define/public (damage dmg)
  (new this% [hp (- hp dmg)] [pos pos] [items items]))