2024年Clojure调查问卷!中分享您的想法。

欢迎!请查看关于页面以了解更多有关该功能的信息。

0
core.logic

因此,具有默认逻辑的标签化数据结构在关系上下文中可能很有趣。比如,您有一个关于狗的一些默认逻辑的关系。

`
(defna friendlyo [Dog-Or-Breed]

([:Spot] succeed)
([:Spike] fail)
([Other-Dog] (fresh [Breed] (dog-breed Other-Dog Breed) (friendlyo Breed)))
([(breed :miniature-dachshund)] fail)
([(breed :golden-retriever)] succeed)
;. . .)

`

假设有一位宏(defmacro breed (link: t) `(link: :breed ~t)).

这比在其中放入(link: :breed :golden-retriever)等要好,因为它是编译时检查的,减少出错的可能性,减少了重复,等等。

这个小补丁使得ex*在模式中扩展宏,因此它不会把例如(breed :golden-retriever)视为引入一个名为“breed”的新LVar。还提供了测试。

10 个答案

0

评论者:dnolen

我对此感到惊讶,这不是已经工作了吗?我们已经支持在模式中统一表达式了。查看master分支中的tests.clj的第1230行。

所以这应该正常工作,我不认为有必要显式支持宏。如果它不起作用,那么可能存在一个错误。

0
_评论者:joeosborn_

至少在0.7.5版本中,对宏的匹配会产生运行时错误


Exception in thread "main" java.lang.ClassCastException: clojure.core.logic.LVar cannot be cast to clojure.lang.IFN
    at rl.core$glyph_$fn__123$fn__144$fn__165$fn__166$_inc__167$fn__168.invoke(core.clj:61)
    at clojure.core.logic.Substitutions.bind(logic.clj:211)
    at rl.core$glyph_$fn__123$fn__144$fn__165$fn__166$_inc__167.invoke(core.clj:58)
    at clojure.core.logic$fn__1056$_inc__1057.invoke(logic.clj:1160)
    at clojure.core.logic$fn__1056$_inc__1057.invoke(logic.clj:1160)
    at clojure.core.logic$fn__898$_inc__899.invoke(logic.clj:823)
    at clojure.core.logic$fn__890$fn__891.invoke(logic.clj:828)


用函数代替宏也会出现同样的情况


Exception in thread "main" java.lang.ClassCastException: clojure.core.logic.LVar cannot be cast to clojure.lang.IFN
    at rl.core$drawable_$fn__235$fn__248$fn__249$_inc__250$fn__251.invoke(core.clj:67)
    at clojure.core.logic.Substitutions.bind(logic.clj:211)
    在 rl.core$drawable_$fn__235$fn__248$fn__249$_inc__250.invoke(core.clj:65)
    at clojure.core.logic$fn__1056$_inc__1057.invoke(logic.clj:1160)
    在 clojure.core.logic$fn__894$_inc__895.invoke(logic.clj:826)
    at clojure.core.logic$fn__1056$_inc__1057.invoke(logic.clj:1160)
    at clojure.core.logic$fn__898$_inc__899.invoke(logic.clj:823)
    at clojure.core.logic$fn__898$_inc__899.invoke(logic.clj:823)
    at clojure.core.logic$fn__898$_inc__899.invoke(logic.clj:823)
    at clojure.core.logic$fn__890$fn__891.invoke(logic.clj:828)


这里是 (glyph-) 用于参考(不要在意所有的额外 [], 我因为要在一个时间数据库中维护事实身份的便利而有一个奇怪的键/值对)

(defna glyph- [Key Val]
    [[[thing] [glyph]] (thing- [thing]) (on-fire_ *turn* [thing]) (== glyph δ)])
    [[[thing] [glyph]] (thing- [thing]) (fresh [Type] (type- [thing] [Type]) (glyph- [Type] [glyph]))]
    [[(type-enum :player)] [glyph]] (== glyph @)
    [[(type-enum :dragon)] [glyph]] (== glyph D)
    [[type] [glyph]] (== glyph ?))


以及 type-enum 作为宏

(defmacro type-enum [v] `[:enum :type ~v])


以及作为函数

(defn type-enum [v] [:enum :type ~v])


我会试验一下,看看我的示例在 HEAD 上是否工作。
0

评论者:joeosborn

HEAD 中这个测试用例有同样的异常(抱歉关于所有这些事实)

`
(defrel thing- [thing])
(defrel type- [thing] [type])
(fact thing- [0])
(fact thing- [1])
(fact thing- [2])
(fact type- [0] [:player])
(fact type- [1] [:dragon])
(fact type- [2] [:pig])
(defn type-enum [t] [:type t])
(defna drawable- [Key]
[[[thing]] (thing- [thing]) (fresh [Type] (type- [thing] [Type]) (drawable- [type])))
[[(type-enum :player)]] succeed)
[[(type-enum :dragon)]] succeed)

(deftest do-fns-work)

(is (= (run* [q] (drawable- [q])) '(0 1))))

`

现在看看,我可能期望一个错误格式的返回值,但重点是,我没有走到那一步。

使用 REPL,我检查了 (defna drawable- ...) 的展开情况(稍微整理了一下)

`
(def drawable- (clojure.core/fn ([Key]
(clojure.core.logic/conda

  ((clojure.core.logic/fresh [Thing] (clojure.core.logic/== [Thing] Key) (thing- [Thing]) (fresh [Type] (type- [Thing] [Type]) (drawable- [Type])))) 
	((clojure.core.logic/fresh [type-enum] 
	  (clojure.core.logic/== [(type-enum :player)] Key) succeed))
	((clojure.core.logic/fresh [type-enum] 
	  (clojure.core.logic/== [(type-enum :dragon)] Key) succeed))))))

`

注意到 (clojure.core.logic/fresh (link: type-enum) ...) 形式,这就是我在这个情况下不想看到的。

我真的不确定为什么这里不工作,而在匹配测试用例中工作。

0

评论者:dnolen

[(type-enum :dragon)]

这个模式似乎表明你想要进行匹配

[[:type :dragon]]

注意这里多了 brackets 层级。这是否是这种情况?

即使如此,我同意展开似乎不太正确。我们永远不应该下沉为这样一个 seq 形式。

0

评论者:joeosborn

是的,这正是这个情况下我天真的解释中期望的输出结果——一个标签值。它失败的原因而不是 :1230 测试用例的原因是它产生了一个向量而不是一个列表吗?将 fn 返回类型改为列表而不是向量似乎也没有帮助。

我的补丁(fwiw)没有表现出这种行为(至少对于宏来说,我没有用 fn 测试过)。

0

评论者:dnolen

我的意思是您不希望这样吗?

(defna drawable- [Key] ([[Thing]] (thing- [Thing]) (fresh [Type] (type- [Thing] [Type]) (drawable- [Type]))) ([(type-enum :player)] succeed) ([(type-enum :dragon)] succeed))

请注意,我删除了一层括号。

0
_评论者:joeosborn_

不!我实际上都想要。我正在做一些时态逻辑相关的工作,并为“更新”流体(fluent)提供一些便利,所以我想要区分参数的“键 part”和“值 part”。对于没有“值 part”的命题来说这看起来很愚蠢,但它允许我编写类似这样的程序和函数:


(defrel heldo 时间 流体)
(defrel ¬heldo 时间 流体)
(declare fluent-obtainedo) ;最近的 'held' 没有被 '¬held' 终止,或者失败
(defn alter-fluent [时间 关系 键 新值]
  ;todo: 错误检查,确保旧值 != 新值,旧值可以获得,新值不能获得
  (doseq [old-val (run* [old-val] (fluent-obtainedo 时间 [关系 键 old-val]))]
    (fact ¬heldo 时间 [关系 键 old-val]))
  (fact heldo 时间 [关系 键 新值]))
. . .
(fact heldo 0 ['pos [0] [0 0]])
. . .
(alter-fluent 1 'pos [0] [1 1])


我还会用这种方法编写所有非时态的流体,以保持一致性和帮助防止错误。
0

评论者:dnolen

我将在周末再仔细看看这个问题。

0

评论者:dnolen

在这里我们正在考虑一个更通用的解决方案:[http://github.com/clojure/core.logic/wiki/Better-syntax-support](http://github.com/clojure/core.logic/wiki/Better-syntax-support)

0
参考:[https://clojure.atlassian.net/browse/LOGIC-44](https://clojure.atlassian.net/browse/LOGIC-44) (由 alex+import 报告)
...