想象一下,我有不同菜肴的食谱和我厨房里含有各种成分的食品。我想使用core.logic
构建一个模型,这将使我能够回答以下问题:对于一组给定的成分(即我现在的那些成分),我可以制作哪些食谱?
食谱有点灵活,我需要能够对此进行建模。后来我想给他们增加数量,但是为了开始我们暂时不要这样做。
我可以看到如何模拟储藏室:
(db-rel in-larder x)
(def larder (db
[in-larder :carrots]
[in-larder :rice]
[in-larder :garlic]))
配方有一个名称和成分列表,可以是可选的或以各种方式组合。有 n 食谱。作为一个例子,食谱可能会(非正式地)看起来像这样:
Risotto A
=========
(carrots OR peas)
rice
(onions OR garlic)
Risotto B
=========
((carrots AND onions)) OR (rice AND peas))
garlic
我正在努力解决如何在core.logic
中表达这一点。 (N.B.上面的文字只是说明性的,并不是机器可读的。)
我想这个查询看起来像这样:
(with-dbs [larder recipes] (run* [q] (possible-recipe q)))
将返回以下结果(给定上面的储存器定义):
(:risotto-a :risotto-b)
我的问题是:我如何对这些食谱进行建模,以便我可以在配方和食品上写一个查询,根据食品的当前内容列出可能配方的名称?
答案 0 :(得分:1)
以下是建模此问题的一种方法:
(db-rel in-larder i)
(db-rel recipe r)
(db-rel in-recipe r i)
(db-rel compound-ingredient i is)
(def recipes (db
[compound-ingredient :carrots-or-peas [:or :carrots :peas]]
[compound-ingredient :onions-or-garlic [:or :onions :garlic]]
[compound-ingredient :carrots-and-onions [:and :carrots :onions]]
[compound-ingredient :rice-and-peas [:and :rice :peas]]
[compound-ingredient :carrots-onions-or-rice-peas [:or :carrots-and-onions :rice-and-peas]]
[recipe :risotto-a]
[recipe :risotto-b]
[in-recipe :risotto-a [:carrots-or-peas :rice :onions-or-garlic]]
[in-recipe :risotto-b [:garlic :carrots-onions-or-rice-peas]]))
(defn possible-recipe [r]
(recipe r)
(fresh [ingredients]
(in-recipe r ingredients)
(all-ingredients-in-lardero ingredients)))
每种食谱都有食谱和成分列表。每种成分可以是单一成分或复合成分,在这种情况下,它可以含有任选或强制成分。
我们需要更多关系才能使其发挥作用:
(defne any-ingredient-in-lardero [ingredients]
([[?i . ?morei]] (conda [(ingredient-in-lardero ?i)]
[(emptyo ?morei) fail]
[(any-ingredient-in-lardero ?morei)])))
(defne all-ingredients-in-lardero [ingredients]
([[?i . ?morei]]
(ingredient-in-lardero ?i)
(conda [(emptyo ?morei)]
[(all-ingredients-in-lardero ?morei)])))
(defn ingredient-in-lardero [i]
(conde
[(fresh [composition op sub-ingredients]
(compound-ingredient i composition)
(conso op sub-ingredients composition)
(conde
[(== :or op) (any-ingredient-in-lardero sub-ingredients)]
[(== :and op) (all-ingredients-in-lardero sub-ingredients)]))]
[(in-larder i)]))
现在我们可以查询不同的食品来获取食谱:
(def larder-1 (db [in-larder :carrots] [in-larder :rice] [in-larder :garlic]))
(def larder-2 (db [in-larder :peas] [in-larder :rice] [in-larder :garlic]))
(with-dbs [recipes larder-1]
(run* [q]
(possible-recipe q)))
;=> (:risotto-a)
(with-dbs [recipes larder-2]
(run* [q]
(possible-recipe q)))
;=> (:risotto-a :risotto-b)
完整代码位于this gist