lisp更新列表函数

lisp更新列表函数,lisp,common-lisp,clisp,Lisp,Common Lisp,Clisp,嘿,所以我试着在lisp中创建一个函数,它包含三个参数,一个跑步者列表,一个名字和一个奖牌类型。跑步者列表如下所示: ((bolt ((gold 4)(silver 2))) (farah ((gold 3)(silver 1)(bronze 1))) (ottey ((bronze 3)))) 我正在尝试更新每位跑步者的奖牌类型和数量,例如,如果我希望博尔特获得4枚金牌,那么我可以使用此功能相应地更新列表。我对lisp非常陌生,我很难做到这一点,我曾尝试使用dolist()在列表中循环,但我

嘿,所以我试着在lisp中创建一个函数,它包含三个参数,一个跑步者列表,一个名字和一个奖牌类型。跑步者列表如下所示:

((bolt ((gold 4)(silver 2)))
(farah ((gold 3)(silver 1)(bronze 1)))
(ottey ((bronze 3))))
我正在尝试更新每位跑步者的奖牌类型和数量,例如,如果我希望博尔特获得4枚金牌,那么我可以使用此功能相应地更新列表。我对lisp非常陌生,我很难做到这一点,我曾尝试使用dolist()在列表中循环,但我很难理解它背后的逻辑。我该怎么做呢

(defun update (type name list) 
    (setf medal (get-runner(name *runner)) )
    (if  ((assoc ‘medal medals) != nil) ;
        (setf count (assoc ‘medal medals)+1)
        (new-list (assoc ‘medal medals) count)




因此,首先,让我们将这些列表称为
((键值)…)
mlists(如果您愿意,用于“奖牌列表”):它们实际上是关联列表(alist),但关联列表通常是
((键值)…)
,所以我想要另一个名称

让我们编写一个通用函数
updatemlist
来更新mlist。它将:

  • 如果无事可做,就停止
  • 否则,如果mlist的第一个元素是它正在查找的元素,则对该元素的值调用其updater函数并返回一个新的mlist
  • 否则,返回一个包含现有第一个元素的新mlist,并更新mlist的其余部分
这是:

(defun update-mlist (mlist key updater)
  ;; update an mlist, replacing the element with key KEY by calling
  ;; UPDATER on its value.  An mlist is of the form ((key value) ...).
  (cond 
   ((null mlist)
    ;; no more to process: we're done
    '())
   ((eql (first (first mlist)) key)
    ;; found it: call the updater on the value and return the new
    ;; mlist
    (cons (list (first (first mlist))
                (funcall updater (second (first mlist))))
          (rest mlist)))
   (t 
    ;; didn't find it: search the rest
    (cons (first mlist)
          (update-mlist (rest mlist) key updater)))))
我们可以试试这个:

> (update-mlist '((able 1) (baker 2) (charlie 2))
                'charlie
                (lambda (v)
                  (+ v 1)))
((able 1) (baker 2) (charlie 3))

现在,让我们将奖牌列表存储在一个变量中,这样我们就可以讨论它了:

(defvar *medals* '((bolt ((gold 4)
                          (silver 2)))
                   (farah ((gold 3)
                           (silver 1)
                           (bronze 1)))
                   (ottey ((bronze 3)))))
*奖牌*
的有趣之处在于它是一个mlist,其中每个元素的值都是一个mlist。因此,我们要做的是使用
updatemlist
更新程序函数本身调用
updatemlist
来更新奖牌列表。好吧,我们可以这样写:

(defun update-medals (medals person medal updater)
  ;; update the medal mlist for PERSON, calling UPDATER on the value
  ;; of the MEDAL medal
  (update-mlist medals person
                (lambda (medal-mlist)
                  (update-mlist medal-mlist
                                medal
                                updater))))
就这样。假设法拉刚刚赢得了一枚金牌:我们想让他们的
金牌数增加1:

> (update-medals *medals* 'farah 'gold
                 (lambda (count)
                   (+ count 1)))
((bolt ((gold 4) (silver 2)))
 (farah ((gold 4) (silver 1) (bronze 1)))
 (ottey ((bronze 3))))
但我们有一个小问题:

>  (update-medals *medals* 'ottey 'gold
                  (lambda (count)
                    (+ count 1)))
((bolt ((gold 4) (silver 2)))
 (farah ((gold 3) (silver 1) (bronze 1)))
 (ottey ((bronze 3))))
哦,天哪

因此,我们可以解决这个问题:让我们更改
更新mlist
,这样,如果它到达mlist的末尾,它将提供一个后备:

(defun update-mlist (mlist key updater fallback)
  ;; update an mlist, replacing the element with key KEY by calling
  ;; UPDATER on its value.  An mlist is of the form ((key value) ...).
  ;; If we reach the end of the list add an entry for KEY with FALLBACK
  (cond 
   ((null mlist)
    ;; no more to process: add the fallback
    (list (list key fallback)))
   ((eql (first (first mlist)) key)
    ;; found it: call the updater on the value and return the new
    ;; mlist
    (cons (list (first (first mlist))
                (funcall updater (second (first mlist))))
          (rest mlist)))
   (t 
    ;; didn't find it: search the rest
    (cons (first mlist)
          (update-mlist (rest mlist) key updater fallback)))))
我们可以测试这一点:

> (update-mlist '((able 1) (baker 2) (charlie 3))
                'zebra
                (lambda (v)
                  (+ v 1))
                26)
((able 1) (baker 2) (charlie 3) (zebra 26))
我们需要相应地更改
更新奖牌

(defun update-medals (medals person medal updater fallback)
  ;; update the medal mlist for PERSON, calling UPDATER on the value
  ;; of the MEDAL medal.  If there is no entry add a fallback.  If
  ;; there is no entry for the person add a fallback as well
  (update-mlist medals person
                (lambda (medal-mlist)
                  (update-mlist medal-mlist
                                medal
                                updater
                                fallback))
                (list medal fallback)))
这是有效的:

> (update-medals *medals* 'ottey 'gold
                 (lambda (count)
                   (+ count 1))
                 1)
((bolt ((gold 4) (silver 2)))
 (farah ((gold 3) (silver 1) (bronze 1)))
 (ottey ((bronze 3) (gold 1))))

> (update-medals *medals* 'hercules 'gold
                 (lambda (count)
                   (+ count 100))
                 100)
((bolt ((gold 4) (silver 2)))
 (farah ((gold 3) (silver 1) (bronze 1)))
 (ottey ((bronze 3)))
 (hercules (gold 100)))
好的,最后我们可以将这一切包装在一个
奖励奖章
函数中:

(defun award-medal (medals person medal &optional (number 1))
  (update-medals medals person medal
                 (lambda (c)
                   (+ c number))
                 number))
现在呢

> (award-medal *medals* 'bolt 'gold)
((bolt ((gold 5) (silver 2)))
 (farah ((gold 3) (silver 1) (bronze 1)))
 (ottey ((bronze 3))))

> (award-medal *medals* 'ottey 'gold)
((bolt ((gold 4) (silver 2)))
 (farah ((gold 3) (silver 1) (bronze 1)))
 (ottey ((bronze 3) (gold 1))))

> (award-medal *medals* 'hercules 'diamond 10000)
((bolt ((gold 4) (silver 2)))
 (farah ((gold 3) (silver 1) (bronze 1)))
 (ottey ((bronze 3)))
 (hercules (diamond 10000)))
> (award-medals *medals*
                '((bolt gold) (ottey silver) (farah bronze)))
((bolt ((gold 5) (silver 2)))
 (farah ((gold 3) (silver 1) (bronze 2)))
 (ottey ((bronze 3) (silver 1))))
你可能已经注意到,每次我调用这些函数中的一个,就好像这是第一次:因为它们是函数,它们有参数和返回值,它们返回的值是新的结构:它们不会破坏性地修改它们的参数。这意味着它们更容易推理和理解,因为它们就是所谓的,并且它们可以轻松、安全地组合:

> (award-medal (award-medal *medals* 'bolt 'gold)
               'ottey 'silver)
((bolt ((gold 5) (silver 2)))
 (farah ((gold 3) (silver 1) (bronze 1)))
 (ottey ((bronze 3) (silver 1))))
我们也可以编写一个小函数来实现这一点:

(defun award-medals (medals award-mlist)
  (if (null award-mlist)
      medals
    (award-medals (award-medal medals
                               (first (first award-mlist)) 
                               (second (first award-mlist)))
                  (rest award-mlist))))
现在呢

> (award-medal *medals* 'bolt 'gold)
((bolt ((gold 5) (silver 2)))
 (farah ((gold 3) (silver 1) (bronze 1)))
 (ottey ((bronze 3))))

> (award-medal *medals* 'ottey 'gold)
((bolt ((gold 4) (silver 2)))
 (farah ((gold 3) (silver 1) (bronze 1)))
 (ottey ((bronze 3) (gold 1))))

> (award-medal *medals* 'hercules 'diamond 10000)
((bolt ((gold 4) (silver 2)))
 (farah ((gold 3) (silver 1) (bronze 1)))
 (ottey ((bronze 3)))
 (hercules (diamond 10000)))
> (award-medals *medals*
                '((bolt gold) (ottey silver) (farah bronze)))
((bolt ((gold 5) (silver 2)))
 (farah ((gold 3) (silver 1) (bronze 2)))
 (ottey ((bronze 3) (silver 1))))

最后两件事:

  • 更新mlist(两个版本)的“错误”是什么。如果你的mlist中有很多人,会发生什么
  • 你能不能写一个版本的
    奖励奖牌
    ,它并不真正关心奖牌授予的整个过程,它只会为任何功能做这个把戏?那有用吗

  • 您已将其标记为
    emacs
    clisp
    。如果你指的是编辑Emacs,那与问题无关。如果您指的是elisp,Emacs的编程语言,那么它和clisp是两种不同的语言,您应该澄清您使用的是哪种语言。@amalloy hi我正在使用Emacs编辑器编写它,我正在lisp“更新列表”中编写它:您应该指定是要使用更新的值创建一个新列表,还是要执行以下操作:旧列表的“就地更新”(即副作用)。@Renzo我想进行就地更新,但我也愿意创建一个新列表。您的代码中有几个语法错误。请记住,调用函数和运算符时总是使用前缀符号(/=AB)而不是(a!=b),括号必须用得恰当。你们可以用一些好的介绍材料。网上有很多是免费的。