请在 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 版本中,与宏匹配会导致运行时错误


在主线程中发生异常 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 代替宏会产生相同的结果


在主线程中发生异常 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- [Key Val]
    [[[东西] [符号]] (东西- [东西]) (燃烧_ *回合* [东西]) (== 符号 \δ))
    [[[东西] [符号]] (东西- [东西]) (新鲜 [类型] (类型- [东西] [类型]) (符号- [类型] [符号])))
    [[(类型-枚举 :玩家)] [符号]] (== 符号 \@))
    [[(类型-枚举 :龙)] [符号]] (== 符号 \D))
    [[类型] [符号]] (== 符号 \?)))


并且 type-enum 是一个宏

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


并且作为一个函数

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


我将尝试并看我的例子在HEAD是否工作。
0

评论者:joeosborn

HEAD中的这个测试案例也会出现相同的异常(对不起,这里有很多事实)

`
(defrel 东西- [东西])
(defrel 类型- [东西] [类型])
(fact 东西- [0])
(fact 东西- [1])
(fact 东西- [2])
(fact 类型- [0] [:玩家])
(fact 类型- [1] [:龙])
(fact 类型- [2] [:猪])
(defn 类型-枚举 [t] [:类型 t])
(defna 可绘制- [Key])
([[东西]] (东西- [东西]) (新鲜 [类型] (类型- [东西] [类型]) (可绘制- [类型])))
([[(类型-枚举 :玩家)]] 成功)
([[(类型-枚举 :龙)]] 成功))

(deftest do-fns-work)

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

`

现在我来看看,我可能期望一个错误格式的返回值,但关键是我不甚至走那么远。

使用REPL,我检查了(defna 可绘制- ...)的展开情况(略有整理)

`
(def 可绘制- (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 (链接: 类型-枚举) ...)形式,这正是我绝对不希望在这次看到的。

我实在不清楚为什么这里不工作,而匹配测试案例却可以工作。

0

评论由:dnolen 发布

[(类型-枚举 :龙)]

这个模式会让你觉得你想要匹配

[[:类型 :龙]]

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

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

0

评论者:joeosborn

是的,这正是在这个案例中期望的结果——一个带有标签的值,按照我朴素的理解。它失败的原因,而:1230的测试没有失败,是因为它产生了向量而不是列表?将函数更改为返回列表而不是向量似乎并没有帮忙。

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

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_ 发布

不,我确实是想要两者都有。我正在做一些时间逻辑的工作,并想要为“更新”一个流态提供一些便利,因此我想要区分参数的“键部分”和“值部分”。对于没有“值部分”的事实看起来很傻,但它让我可以编写类似这样的程序和函数:


(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

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