在LispWorks中进行编程21:食谱
Category:UI界面编写食谱
曾经看过厨房橱柜,想知道你可以做什么晚餐?然后这个程序就是答案。您首先选择您可用的成分:
然后它会告诉您可以制作的食谱:
您可以向数据库添加新配方,并更新配料列表。
完整列表
描述
配方程序使用两个全局变量。第一个,成分数据库,包含我们将要使用的所有成分的列表:
(defparameter ingredient-database ‘(“eggs” “flour” “butter” “chicken” “beef” “pork” “lamb” “sugar” “chocolate” “onions” “fish” “tomatoes” “pasta” “chorizo” “rice” “potatoes” “cheese”))
第二个是recipe-database,它将包含一个食谱列表。每个食谱都是三个项目的列表:
- 食谱的名称。
- 成分列表。
- 该方法的简短描述。
因此,在添加了几个配方之后,recipe-database可能如下所示:
((“Cheese omelette” (“eggs” “cheese”) “Beat the eggs, cook, and add the cheese”) (“Pizza” (“flour” “tomatoes” “chorizo” “cheese”) “Make a dough, add tomato, cheese, and chorizo, and bake for 12m at 210°C”))
基本惯例
我们的出发点是程序包含测试成分是否包含在成分列表。我们将这样使用它:
CL-USER > (contains “chicken” ‘(“pork” “chicken” “rice”))T
但:
CL-USER > (contains “chicken” ‘(“pork” “chocolate” “rice”))NIL
英文定义如下:
要查看成分是否在成分列表中:
- 如果列表为空,则答案为否。
- 如果该成分是列表中的第一项,那么答案是肯定的。
- 否则它就是问题的答案 – 除了第一个元素之外,其余成分中的成分是什么?
这是Lisp过程的定义:
(defun contains (item list) (if (null list) nil (if (string= item (first list)) t (contains item (rest list)))))
基于此,我们定义了一个过程子集,用于检查成分列表lista是否是列表listb的子集。我们将使用如下:
CL-USER > (subset ‘(“pork” “rice”) ‘(“pork” “eggs” “rice”))T
但:
CL-USER > (subset ‘(“pork” “eggs” “rice”) ‘(“pork” “rice”))NIL
在英语中,这定义如下:
检查lista是否是listb的子集
- 如果lista为空,那么答案是肯定的。
- 如果listb不包含lista的第一个元素,那么答案是否定的
- 否则它就是问题的答案 – lista的其余部分排除第一个元素是listb的一个子集吗?
作为Lisp程序,它变成:
(defun subset (lista listb) (if (null lista) t (if (null (contains (first lista) listb)) nil (subset (rest lista) listb))))
食谱计划
现在我们将定义一个程序,找到您可以使用一组特定成分制作的所有食谱。我们将这样称呼它:
CL-USER > (recipes-can-make ‘(“cheese” “eggs”) recipe-database)((“Cheese omelette” (“eggs” “cheese”) “Beat the eggs, cook, and add the cheese”))
英文定义是:
要找到您可以使用配料制作的食谱:
- 如果食谱列表为空,则回答无。
- 如果第一个配方的成分是可用成分列表的子集,则返回该配方以及检查剩余配方的结果。
- 否则只返回检查剩余配方的结果。
这是Lisp中的过程:
(defun recipes-can-make (ingredients recipes) (if (null recipes) nil (let* ((entry (first recipes)) (needs (second entry))) (if (subset needs ingredients) (cons entry (recipes-can-make ingredients (rest recipes))) (recipes-can-make ingredients (rest recipes))))))
用户界面
最后,我们添加一些对话框,以便更容易地添加和查找食谱。这是添加配方的过程:
(defun add-recipe () (let ((name (capi:prompt-for-string “What’s the recipe?”)) (ingredients (capi:prompt-for-items-from-list ingredient-database “What does it need?”)) (method (capi:prompt-for-string “Brief method:”))) (setq recipe-database (cons (list name ingredients method) recipe-database))))
现在这里是查找食谱的界面:
(defun find-recipe () (let ((ingredients (capi:prompt-for-items-from-list (sort ingredient-database #’string<) “What ingredients do you have?”))) (capi:prompt-with-list (recipes-can-make ingredients recipe-database) “You can make these:”)))
保存和加载数据库
最后,这是将数据库保存到磁盘上的文件的过程:
(defun save-recipes () (with-open-file (stream “Recipes” :direction :output :if-exists :supersede) (write ingredient-database :stream stream) (write recipe-database :stream stream)))
并将它们加载回:
(defun load-recipes () (with-open-file (stream “Recipes” :direction :input) (setf ingredient-database (read stream)) (setf recipe-database (read stream))))
http://mip.i3geek.com