如何操作一系列的lvars

时间:2017-05-09 17:57:17

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

假设我想获得相当于给定值的账单/硬币面额的所有组合,同时给出一组可用面额。

例如,对于(change 14 #{1 2 5 10}),我期待

(
    {10 1, 5 0, 2 2, 1 0}
    {10 1, 5 0, 2 1, 1 2}
    {10 0, 5 2, 2 2, 1 0}
    {10 0, 5 2, 2 1, 1 2}
    ;; ...
)

我的尝试是

(defn change [amount denominations]
  (let [dens (sort > denominations)
        vars (repeatedly (count dens) lvar)]
    (run* [q]
      (== q (zipmap dens vars))
      (everyg #(fd/in % (fd/interval 0 amount)) vars)
      (== amount (apply + (map * dens vars))))))

但自然最后一行不起作用。我还没有找到一种方法来对reduce序列进行某种vars,或者用其他方式来设置对每个lvar单独无效的目标,但是对于整体(同时也在做)一些具有外部值的操作,在此示例中为amountdenominations

1 个答案:

答案 0 :(得分:2)

  

我还没有找到一种方法来设置对每个lvar单独无效的目标,但是对于整体(同时在本例中还使用外部值,金额和面额进行一些操作)

这样做的一种方法是定义递归关系函数,该函数采用逻辑vars,面额和期望的sum,并使用conso为每对设置目标varsdens个项目:

(defn productsumo [vars dens sum]
  (fresh [vhead vtail dhead dtail product run-sum]
    (conde
      [(emptyo vars) (== sum 0)]
      [(conso vhead vtail vars)
       (conso dhead dtail dens)
       (fd/* vhead dhead product)
       (fd/+ product run-sum sum)
       (productsumo vtail dtail run-sum)])))

请注意freshvars的头部和尾部的dens逻辑变量,product以存储每个&#的头部产品的run-sum 34;传递"和sum变量,用于约束所有产品的总和,使它们等于consovars和递归的组合允许我们为整个dens(defn change [amount denoms] (let [dens (sort > denoms) vars (repeatedly (count dens) lvar)] (run* [q] (== q (zipmap dens vars)) (everyg #(fd/in % (fd/interval 0 amount)) vars) (productsumo vars dens amount)))) 设置目标。

然后将其插入现有功能:

(change 14 #{1 2 5 10})
=>
({10 0, 5 0, 2 0, 1 14}
 {10 1, 5 0, 2 0, 1 4}
 {10 0, 5 1, 2 0, 1 9}
 {10 0, 5 0, 2 1, 1 12}
 {10 1, 5 0, 2 1, 1 2}
 {10 1, 5 0, 2 2, 1 0}
 {10 0, 5 0, 2 2, 1 10}
 {10 0, 5 2, 2 0, 1 4}
 {10 0, 5 1, 2 1, 1 7}
 {10 0, 5 0, 2 3, 1 8}
 {10 0, 5 0, 2 4, 1 6}
 {10 0, 5 1, 2 2, 1 5}
 {10 0, 5 0, 2 5, 1 4}
 {10 0, 5 2, 2 1, 1 2}
 {10 0, 5 0, 2 6, 1 2}
 {10 0, 5 1, 2 3, 1 3}
 {10 0, 5 0, 2 7, 1 0}
 {10 0, 5 2, 2 2, 1 0}
 {10 0, 5 1, 2 4, 1 1})

最后得到答案:

var myObject = {
  myAlert: function(str) {
    alert(str);
  }
};
myObject.myAlert('Hello');

var MyConstructor = function() {
};
MyConstructor.myAlert = function(str) {
  alert(str);
}
MyConstructor.myAlert('Bye');

我怀疑可能有更简洁/优雅的解决方案,但这很有效。