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

欢迎!请参阅关于页面了解更多本网站的信息。

0
core.logic

我有一个装箱问题,这个问题与在这篇博客文章中描述和解决的问题有一定的关联。以下是代码,转录时增加了一处

(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})

当运行时,与我预期并通常在调用 project 时所看到的不同,我没有得到 vhead 的投影或当前值,而是得到了 Lvar。有没有任何想法解释为什么会出现这种情况呢?

我的特定用例是对 productsumo 的修改,我有一个键和权重的映射,我需要用它来代替这里的 coll dens。我的初始方法——看起来是合理的——是像上面一样使用 project 来对基于 vhead 当前值的成本 LVar 进行统一,然后在该计算中使用它。目前我只能得到 LVar 而不是值。

有想法吗?

1 个答案

0

已选择
 
最佳答案

从 project 中得到 lvar 的原因是没有“LVar vhead 的当前值”

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 的支持相对较少,很高兴得到您的回复。


>这主要意味着它非常依赖于顺序

这很有道理。然而,在提交的 conde 表达式中的目标,在投影之前先绑定 `vhead`;除非我遗漏了关于 conde 中目标顺序的一些东西(他们提到了关于目标交错的一些内容)。除非目标顺序完全任意(我不这么认为,因为我们明确地对目标进行排序以优化查询和剪枝搜索空间)。
仅因为 vhead 在早期目标中使用,并不意味着它是闭包的(有一个确定的值)。传递的 vars seq 是一个 lvars 序列,每个都是有限域中的约束,但它们不是闭包的,vhead 与 vars 的第一个元素统一(这是 conso 做的)。因此,vhead 不是闭包的。

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