我是 Lisp 新手,在递归和函数返回方面存在问题。为了更好地理解和解决我的问题,我提供了以下场景。如果它很冗长,我很抱歉。如果这会激怒其他人,我很乐意将其减少。要直接跳到业务,请从水平线开始阅读。
想象一下酒吧里的女服务员。她没有接受酒水订单,而是强制她的顾客将自己标识为啤酒、朗姆酒、威士忌或这些的某种组合的饮用者。然后她拿起一个装满啤酒、朗姆酒或威士忌的托盘,绕着吧台转了一圈,只给任何自称是该特定饮料饮用者的顾客留下一杯饮料。当她完成每一轮比赛时,她总是坐下来喝一杯长岛冰茶。之后,她又拿起另一盘专门放一种饮料的托盘,再次出去送货。没有顾客可以拒绝喝酒,也没有人可以改变他们的饮料偏好。
现在,Mindy(女服务员)需要一种新颖的方法来跟踪她为每位顾客提供的每种类型的饮料的数量。明迪数学不是很好,到了晚上,所有的长岛冰茶真的加起来了。
所以当她要求一个简单的解决方案来跟踪她的饮料分配时,我自然建议创建一个简单的 Lisp 小程序。工作原理如下:当她完成了一轮美味饮料的送达后,Mindy 只是走到她的 Altair 8800 前并输入以下内容:
(update-orders <order-list> <drink>)
所有顾客的名单和他们的订单在哪里,是她最近一次外出时刚端上来的饮料。
它应该正确地检查顾客名单和他们的饮料数量,将适当的饮料更新一个,而让其他人不理会。为了与适当的计算机系统交互,完成后需要从该函数返回一个新更新的订单列表。
就在今天遇到了一个bug:正确调用函数后,返回的值不是我想要的。该列表每次仅包括列表中第一位顾客的最后一个饮料计数列表。与 Lisp 不同,递归编程是真正的罪魁祸首,我尝试修改代码来解决这个问题,但无济于事。我需要从函数返回的完整列表。
你可能已经猜到了,这个故事不是真的。我试图解决的真正问题与微积分有关,对于那些接触 Lisp 的人来说,这是一个众所周知的话题。然而,我的问题不在于我的分配,而是围绕递归调用并将完整的值列表返回给调用函数,以便我可以构建一个完整的所有术语列表,以便在完成时返回。在我能够解决这个子问题之后,我距离将它应用到我的实际任务并解决它只是一箭之遥。
运行以下函数调用:
(update-orders (quote ( (bill (4 beer) (5 whiskey)) (jim (1 beer)) (kenny (1 whiskey) (4 rum)) (abdul (1 beer) (3 whiskey) (2 rum) ))) (quote beer))
让我返回以下内容:
((5 WHISKEY))
相反,我会喜欢与提供给上述函数的格式相同的列表。
请看下面的代码。为了方便起见,它已被修改为将调试输出包括到屏幕上。功能饮料 list 可能是我的麻烦所在。
(defun update-orders (x d)
(print 'orders)
(prin1 x)
(order (car x) d)
)
(defun order (x d)
(print 'order)
(prin1 x)
(drink-list (cdr x) d)
)
(defun drink-list (x d)
(print 'drink-list)
(prin1 x)
;(append
;(cons
;(list
(drink-count (car x) d)
(cond
((cdr x) (drink-list (cdr x) d))
(t x)
)
;)
)
(defun drink-count (x d)
(print 'drink-count)
(prin1 x)
(list
(cond
((eq (car (cdr x)) d)
(modify-count (car x) 1))
(t x)
)
)
)
(defun modify-count (x d)
(print 'modify-count)
(prin1 x)
(print 'new-modify-count)
(prin1 (+ (parse-integer (subseq (write-to-string x) 0)) 1))
(list
(+ (parse-integer (subseq (write-to-string x) 0)) 1)
)
)
编辑:
我已将 ooga 的建议合并到我的代码中。新的 order 和 update-order 函数如下所示:
(defun update-orders (x d)
(cond
((null x) ())
(t (cons (order (car x) d) (update-orders (cdr x) d)))
)
)
(defun order (x d)
;(print 'order)
;(prin1 x)
(drink-list (cdr x) d)
)
我现在返回以下列表,运行与上面相同的函数调用:
(((5 WHISKEY)) ((1 BEER)) ((4 RUM)) ((2 RUM)))
这是一个嵌入列表的列表(我相信是 2 深),其中包括列表中每个顾客的所有最后饮品项目和饮品数量(比尔的最终列表条目是 5 杯威士忌,吉姆的最终条目是 1 杯啤酒,等等)。他们的前 n-1 杯饮料不会添加到他们的饮料返回列表中。
我误读了你的建议吗?我有一种感觉,我离这里只有半步之遥。
最佳答案
在更新订单中,您只需将 x 的汽车传递给订单。 x 的其余部分被完全忽略。然后,您只需将 cdr 传递给酒单。
作为如何构建代码的示例,这里有一个程序,它将给定列表的每个成员加 1。
示例调用:(increment-list '(1 2 3))
(defun increment-list (x)
(cond
((null x) ())
(t (cons (increment (car x)) (increment-list (cdr x))))
)
)
(defun increment (x)
(+ x 1)
)
更改
increment-list
至update-orders
和 increment
至orders
(并添加第二个输入等),我认为这应该是您的程序结构。此外,您应该尝试自下而上构建它。尝试编写一个函数,如果(数字饮料)列表中的给定饮料匹配,该函数将在数字上加一。即,鉴于此:
(add-one-if '(4 beer) 'beer)
它应该返回这个
(5 BEER)
鉴于此
(add-one-if '(3 whiskey) 'beer)
它应该返回这个
(3 WHISKEY)
关于recursion - 无法将递归构建的列表返回到 Lisp 中的调用函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21504762/