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* 在模式中扩展宏,这样它就不会将 e.g. (breed :golden-retriever) 视为引入了一个新的 LVar 叫做 "breed"。还提供了测试。

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- [Key Val]
    [[[物品] [符号]] (物品- [物品]) (on-fire_ *turn* [物品]) (== 符号 \δ))
    [[[物品] [符号]] (物品- [物品]) (fresh [类型] (类型- [物品] [类型]) (符号- [类型] [符号])))
    [[(类型-enum :player)] [符号]] (== 符号 \@))
    [[(类型-enum :dragon)] [符号]] (== 符号 \D))
    [[类型] [符号]] (== 符号 \?)))


type-enum 作为一个宏

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


同时也是一个函数

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


我在 HEAD 上尝试一下例子是否可行。
0

评论者:joeosborn

HEAD 中的这个测试用例出现了同样的异常(对不起,所有的这些事实)

`
(defrel 物品- [物品])
(defrel 类型- [物品] [类型])
(fact 物品- [0])
(fact 物品- [1])
(fact 物品- [2])
(fact 类型- [0] [:player])
(fact 类型- [1] [:dragon])
(fact 类型- [2] [:pig])
(defn 类型-enum [t] [:type t])
(defna 可绘制的- [Key])
([[物品]] (物品- [物品]) (fresh [类型] (类型- [物品] [类型]) (可绘制的- [类型])))
([[(类型-enum :player)]] succeed)
([[(类型-enum :dragon)]] succeed))

(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 (链接: 类型-enum) . . .) 表达式,这正是我不希望在此时见到的。

我不太清楚为什么在这里不行,但匹配测试用例中却没有问题。

0

由 dnolen 评论

[(类型-enum :dragon)]

这个模式似乎是想匹配

[[:type :dragon]]

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

即便如此,我同意展开看起来并不太对。我们绝对不应该下降到这样的序列形式。

0

评论者:joeosborn

是的,这就是本例中期望的结果——在我的简单诠释中是一个标记值。但这为什么会在 :1230 上的测试失败,而不是因为这个它正在生成一个向量而不是一个列表?将 fn 改为返回列表而不是向量似乎不起作用。

我的补丁(fwiw)没有显示这种行为(至少对于宏来说是这样,我没有用 fns 测试过)。

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 评论

不!我实际上想要两者都有。我正在做一些时序逻辑的东西,并希望为“更新”流畅度提供一些便捷,所以我想要区分参数的“键部分”和“值部分”。对于没有“值部分”的事实看起来很笨拙,但它让我能够编写如下类似的程序和 fns


(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 报告)
...