请在 2024 Clojure 状态调查 中分享您的想法!

欢迎!请参阅 关于 页面以获得更多有关工作方式的信息。

0
core.logic

我在 Taylor Wood 的这篇博客文章 中描述并解决了与我所解决的问题相似的“凑零钱”问题。以下是代码,添加了1个转录

(ns blah
  (:require [clojure.core.logic :refer :all :as l]
            [clojure.core.logic.fd :as fd]))

(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)
      (project [vhead]
        (do (println vhead) succeed))  ;;<--- Just a lame goal that should print out the head..
      (fd/* vhead dhead product)
      (fd/+ product run-sum sum)
      (productsumo vtail dtail run-sum)])))

(defn change [amount denoms]
  (let [dens (sort > denoms)
        vars (repeatedly (count dens) lvar)]
    (run* [q]
      ;; we want a map from denominations to their quantities
      (== q (zipmap dens vars))
      ;; prune problem space...
      ;; every var/quantity must be 0 <= n <= amount
      (everyg #(fd/in % (fd/interval 0 amount)) vars)
      ;; the real work
      (productsumo vars dens amount))))

user> (change 14 #{1 5 10})
<lvar:81678>
<lvar:81679>
<lvar:81680>
({10 0, 5 0, 1 14} {10 1, 5 0, 1 4} {10 0, 5 1, 1 9} {10 0, 5 2, 1 4})

当运行时,我没有得到预期的 LVar vhead 的投影或当前值,而通常在使用时我在 project 中会看到这样的值,我得到了 Lvar。有想法为什么是这样吗?

我的特定用例是对 productsumo 的修改,其中我需要一个键到重量的映射来代替这里的 coll dens。我的初始方法 - 看起来是合理的 - 是使用上述 project 统一一个基于 vhead 当前值的成本 LVar,然后在使用产品计算中使用它。目前我总是在得到 LVar 而不是值。

有想法吗?

1 个回答

0

已被选中
 
最佳答案

从 project 中得到lvar意味着没有“vhead LVar的当前值”

project 是非关系型的,这很大程度上意味着它非常依赖顺序,

例如

user=> (doall (l/run 1 [q] (l/fresh []  (l/== q 1) (l/project [q] (do (println q) l/succeed)))))
1
(1)
user=> (doall (l/run 1 [q] (l/fresh [] (l/project [q] (do (println q) l/succeed)) (l/== q 1))))
<lvar:q__3358>
(1)
user=>

所以当你得到一个与预期值不符的lvar时,是因为你预期将值分配给lvar的目标还没有执行。

我不知道你在core.logic/prolog/minikanren方面的经验水平如何,但如果你是初学者或在学习,我推荐你忘记这个项目的存在。它可能是一个有用的技巧(用于调试、性能或者为core.logic和其他系统之间的接口编写代码),但如果你的目的是编写逻辑程序,它可能会阻碍你。

感谢您的回复。我想core.logic的支持相对较少,很高兴得到回复。


>这很大程度上意味着它非常依赖于顺序

这很有道理。然而,在提交的cond表达式中的目标在投影之前已经将`vhead`绑定到了cons;除非我在cons中的目标排序方面有什么遗漏(他们提到了关于目标交错的某些内容)。除非目标排序是完全随机的(我不这么认为,因为我们会明确排序目标以优化查询和剪枝搜索空间)。
仅仅因为vhead被用于较早的目标并不意味着它是确定的(具有确定值)。传入的vars序列是一个lvars序列,每个lvars都被约束在有限的域中,但它们并没有确定下来,vhead和vars的第一个元素进行统合(这就是cons所做的事情)。所以vhead并没有确定下来。

交错是指在core.logic(以及minikanren)如何处理搜索树中的分支,并且不会影响目标执行的顺序。这是minikanren和prolog之间经常引用的不同之处。Prolog实际上执行深度优先搜索,如果你有一个分支,并且第一个替代方案没有终止(它会发散,有某种无限循环),并且第二个替代方案在答案中终止,prolog不会产生答案,因为它被第一个替代方案卡住了。Minikanran将先对第一个替代方案做一些工作,然后对第二个替代方案做一些工作,然后回到第一个,等等。
...