2024 年 Clojure 状态调查!中分享你的看法。

欢迎!有关您如何使用本网站的更多信息,请查阅关于页面。

0
core.logic

我有一个问题与在Taylor Wood的这篇博客文章中描述和解决的问题“change-making”问题有点相似。以下是代码,其中包括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})

运行时,未获得预期和正常情况下使用project时看到的 LVar vhead 的投影或当前值,而是得到 Lvar。有什么想法吗?

我的具体用例是修改了 productsumo,在其中,我需要一个从 dens 到 key的映射,在备用方案中使用它。我的初始方法是使用project如上所述来基于 vhead 的当前值统一成本 LVar,然后在乘法运算中使用它。目前,我总是得到 LVar 而不是值。

有什么想法吗?

1 答案

0

选定
 
最佳答案

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

投影是非关系的,这主要意味着它非常依赖顺序,

例如

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


>>这意味着这很大程度上取决于顺序

这很有道理。但是,提交的代码表达式中目标在投影前的绑定结构`vhead`可能会导致这个问题;除非我遗漏了关于conde中目标排序的一些信息(他们提到有关目标是交错这一点的信息)。除非目标排序是完全任意的(我不这么认为,因为我们明确地对目标进行排序以优化查询并修剪搜索空间....)。
仅仅因为vhead在早期目标中使用并不意味着它是确定的(有一个确定的价值)。传递的变量序列是一个lvar序列,每个变量强制在一个有限域中,但它们不是确定的,vhead与变量序列的第一个元素统一(这就是conso所做的)。因此,vhead不是确定的。

交错是关于core.logic(和minikanren)如何处理搜索树中的分支,并不影响目标执行顺序。这是minikanren和prolog之间经常引用的差异。Prolog实际上执行深度优先搜索,如果你有一个分支,第一个选择没有结束(它分散了,有某种无限循环),第二个选择以一个答案结束,Prolog不会被答案卡住,因为它被第一个选择卡住了。minikanran会在第一个选择上做一些工作,然后在第二个选择上做一些工作,然后再回到第一个选择,等等。
...