【问题标题】:Modelling recipes and available ingredients with constraint logic使用约束逻辑对配方和可用成分进行建模
【发布时间】:2015-02-02 16:05:05
【问题描述】:

想象一下,我的厨房里有许多不同菜肴的食谱和一个装有各种食材的储藏室。我想使用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 中表达这一点。 (注意,上面的文字只是说明性的,并不是机器可读的。)

我想查询应该是这样的:

(with-dbs [larder recipes] (run* [q] (possible-recipe q)))

这将返回以下结果(给定上面的储藏室定义):

(:risotto-a :risotto-b)

我的问题是:如何对这些食谱进行建模,以便我可以对食谱和储藏室编写查询,以列出给定储藏室当前内容的可能食谱的名称?

【问题讨论】:

    标签: clojure constraint-programming logic-programming clojure-core.logic minikanren


    【解决方案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

    【讨论】:

    • 很好的答案!我想我一直在努力思考如何使食谱中的布尔表达式变得任意复杂。您给出的答案以简洁的表达方式巧妙地解决了这个问题。
    猜你喜欢
    • 2013-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多