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

当我运行代码时,我得到的不是像预期的那样是使用 project 得到 LVar vhead的投影或当前值,而是得到了 Lvar。有什么想法吗?

我的具体情况是对 productsumo 进行修改,其中我需要使用一个键到重量映射,而不是这里使用的 coll dens。我的初始方法——看似合理——是使用上述 project 来统一成本 LVar,基于当前 vhead 的值,然后将其用于乘法计算。目前我总是在得到 LVars 而不是值。

有什么想法吗?

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


>>这大多意味着它与顺序非常相关

这很有道理。然而,提交的条件表达式中的目标是先绑定`vhead`,然后再进行投影;除非我在conde(目标排序)方面遗漏了某些东西(他们提到了关于目标是交错排列的某事)。除非目标排序完全任意(我不这么认为,因为我们明确地对目标排序以优化查询和剪枝搜索空间……)。
仅仅因为vhead在较早的目标中使用并不意味着它是确定的(具有确定的值)。传递的变量序列是一个lvar序列,每个lvar都限制在有限域中,但它们不是确定的,并且vhead与变量序列的第一个元素统一(这是cons的作用)。因此,vhead不是确定的。

交错是关于core.logic(和minikanren)如何处理搜索树中的分支的问题,并且不会影响目标执行的顺序。这是minikanren和Prolog之间经常引用的差异。Prolog实际上执行深度优先搜索,如果你有一个分支,第一个替代方案不终止(它分支、具有某种无限循环),第二个替代方案以答案终止,Prolog不会生成答案,因为它会卡在第一个替代方案上。Minikanran将稍微处理第一个替代方案,然后稍微处理第二个,然后回到第一个,等等。
...