请在 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)).

这比在其中有名或 whatever 使用 (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)


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


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)
    at 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)
    at 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- [键 值]
    ([[事物] [ глиф]] (事物- [事物]) (on-fire_ *转换* [事物]) (== glasf \δ))
    ([[事物] [ глиф]] (事物- [事物]) (fresh [类型] (类型- [事物] [类型]) ( глиф- [类型] [ глиف])))
    ([[(类型-枚举 :玩家)] [ глиف]] (== glasf \@))
    ([[(类型-枚举 :龙)] [ глиف]] (== glasf \D))
    ([[类型] [ глиフ]] (== glasf \?)))


   type-enum是一个宏

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


   ,也可以作为一个函数

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


   将尝试看看我的示例是否在HEAD中有效。
0

   评论由: joeosborn发表

   HEAD中的这个测试案例也有相同的异常(对不起,所有的美食)

`
   (defrel thing- [事物])
   (defrel type- [事物] [类型])
   (fact thing- [0])
   (fact thing- [1])
   (fact thing- [2])
   (fact type- [0] [:玩家])
   (fact type- [1] [:龙])
   (fact type- [2] [:猪])
   (defn type-enum [t] [:类型 t])
   (defna drawable- [键])
   ([[事物] (事物- [事物]) (新鲜 [类型] (类型- [事物] [类型]) (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 评论:

[[类型-枚举 :龙]]

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

[[:类型 :龙]]

   注意到这里额外的括号层级。这是否是这样?

   即便如此,我也认为展开并不完全正确。我们永远也不应该下降到那种形式的seq形式。

0

   评论由: joeosborn发表

是的,这正是在这个情况下期望的结果——在我的天真理解中是一个带有标签的值。它失败的原因,而与:1230的测试不匹配,是因为它产生了一个向量而不是一个列表吗?将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 评论:

不是这样!我实际上想要两者都有。我在做一些时态逻辑的工作,并且想为“更新”一个流有着便利性,所以我想要区分参数的“键部分”和“值部分”。对于没有“值部分”的事实看起来很荒谬,但它允许我编写类似下面的过程和函数


(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
参考: https://clojure.atlassian.net/browse/LOGIC-44(由 alex+import 报告)
...