微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

lisp 更新列表函数

如何解决lisp 更新列表函数

嘿所以我试图在 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)



解决方法

所以,首先让我们将这些 ((key value) ...) 列表称为 mlist(如果您愿意,可以称为“奖牌列表”):它们实际上是关联列表(alists),但关联列表通常采用 {{ 1}},所以我想要另一个名字。

让我们编写一个通用函数 ((key . value) ...) 来更新 mlist。它会:

  • 无事可做就停下来;
  • 否则,如果 mlist 的第一个元素是它要查找的元素,则对该元素的值调用其更新函数并返回一个新的 mlist;
  • 否则返回一个包含现有第一个元素的新 mlist,并更新 mlist 的其余部分。

这是:

update-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。因此,我们要做的就是使用 *medals*,其中更新程序函数本身调用 update-mlist 来更新奖牌列表。好吧,我们可以这样写:

update-mlist

就是这样。假设 (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)))) 刚刚赢得一枚金牌:我们希望将他们的 farah 计数增加 1:

gold

但是我们有一个小问题:

> (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 的末尾,它会提供回退:

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

update-medals

这有效:

(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))) 函数中:

award-medal

现在

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

您可能已经注意到,每次我调用这些函数时,就好像这是第一次:那是因为它们是函数,它们有参数和返回值,而这些值它们返回的是新结构:它们不会破坏性地修改它们的参数。这意味着它们更容易推理和理解,因为它们就是所谓的 referentially transparent,并且它们可以轻松安全地组合:

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

最后两件事:

  1. > (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 中真的有很多人,会发生什么?
  2. 你能不能写一个 update-mlist 的版本,它并不真正关心整个奖牌颁发的事情,而且它可以对任何函数执行这个技巧?那会有用吗?

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。