请分享您的想法,填写《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)
;. . .)

`

假设有一个定义好的宏(tech: defmacro breed (link: t) `(tech: link: :breed ~t))。

这比在这里插入(breed :golden-retriever)等表达要好,因为它可以编译时检查,更不易出错,减少重复,等等。

这个小补丁使得ex*在模式中展开宏,因此它不会将(e.g. (breed :golden-retriever))视为引入了一个名为"breed"的新LVar。也提供了一个测试。

10 个答案

0

评论者:dnolen

我很惊讶这还没起作用。我们已经对模式中的表达式支持了统一。看看master分支中的tests.clj的第1230行。

所以这应该可以正常工作,没有必要显式地支持宏,据我所知。如果不起作用,那么可能是一个bug。

0
_评论者:joeosborn_

至少在0.7.5版本中,匹配宏会导致运行时错误


异常在主线程中 "main" 发生 java.lang.ClassCastException: clojure.core.logic.LVar 不能转换成 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)


使用fn而不是宏也会产生相同的问题


异常在主线程中 "main" 发生 java.lang.ClassCastException: clojure.core.logic.LVar 不能转换成 clojure.lang.IFn
    在 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- [键 值]
    ([[事物] [象形]] (事物- [事物]) (在火灾_ *回合* [事物]) (== 象形 \δ))
    ([[事物] [象形]] (事物- [事物]) (新鲜 [类型] (类型- [事物] [类型]) (象形- [类型] [象形])))
    ([[(枚举类型 :玩家)] [象形]] (== 象形 \@))
    ([[(枚举类型 :龙)] [象形]] (== 象形 \D))
    ([[类型] [象形]] (== 象形 \?)))


和 type-enum 作为宏

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


和作为一个函数

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


我将在这里尝试我的示例是否在 HEAD 中工作。
0

评论者:joeosborn

在 HEAD 中这个测试用例也有同样的异常(对不起,关于所有的事实)

`
(defrel thing-) [事物]
(defrel type-) [事物] [类型]
(事实 thing- [0])
(事实 thing- [1])
(事实 thing- [2])
(事实 type- [0] [:玩家])
(事实 type- [1] [:龙])
(事实 type- [2] [:猪])
(defn type-enum [t] [:类型 t])
(defna drawable-) [键]
([[事物]] (事物- [事物]) (新鲜 [类型] (类型- [事物] [类型]) (可绘制- [类型])))
([[(枚举类型 :玩家)]] 成功)
([[(枚举类型 :龙)]] 成功))

(deftest do-fns-work)

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

`

现在看来,我可能期望一个错误的格式返回值,但问题是,我甚至还没有达到这个程度。

使用 REPL,我检查了 (defna drawable-) 的展开(稍作整理)

`
(def drawable- (clojure.core/fn ([键]
(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 (链接:枚举类型) . . .) 形式,这正是我不希望在这个情况下看到的。

我真心不确定为什么这里不工作,而匹配测试用例却可以工作。

0

评论者:dnolen

[(枚举类型 :龙)]

这种模式似乎表明你想要匹配

[[类型 :龙]]

这里多了一层括号。是这样吗?

即使如此,我同意展开看起来并不完全正确。我们永远不应该下降到这样的序列形式。

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_

不,我实际上是想要两个都这样。我正在做一些时态逻辑的事情,并希望有一些方便的“更新”流畅的方式,所以我希望区分参数的“键部分”和“值部分”。对于没有“值部分”的事实看起来很愚蠢,但它允许我编写类似于这样的过程和 fn


(defrel heldo Time Fluent)
(defrel ¬heldo Time Fluent)
(declare fluent-obtainedo) ; 最新的 'held' 没有被 '¬held' 终止,或者失败
(defn alter-fluent [Time Rel Key NewVal]
  ;todo: 错误检查,确保旧值不等于新值,旧值有效,新值无效
  (doseq [old-val (run* [old-val] (fluent-obtainedo Time [Rel Key old-val]))]
    (fact ¬heldo Time [Rel Key old-val]))
  (fact heldo Time [Rel Key NewVal]))
. . .
(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

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