2024 Clojure 状态调查!中分享您的想法。

欢迎!请参阅关于页面以获取更多有关如何使用此功能的信息。

0
core.logic

因此,标记的数据结构可能在关系型环境中很有趣。比如说,你有一个有关狗的默认逻辑的关系。

`
(defn 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 (t: association) `(link: :breed ~t))。

这比将(link: :breed :golden-retriever)等项放在那里要优雅得多,因为它是编译时检查的,减少了错误,减少了代码重复等。

这个小补丁使得ex*可以扩展模式中的宏,因此它不会把例如(breed :golden-retriever)当作引入名为"breed"的新LVar来处理。提供的测试也通过了。

10 个答案

0

评论者:dnolen

我很惊讶这竟然还没有工作。我们已经在模式统一表达式中提供了支持。查看主分支中的tests.clj的第1230行。

所以这应该可以工作,在我看来没有必要明确支持宏。如果不是这样工作,那么可能是有bug。

0
评论者:joeosborn

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


异常在“main”线程 java.lang.ClassCastException: clojure.core.logic.LVar无法转换为clojure.lang.IFn
    在core.clj的61行rl.core$glyph_$fn__123$fn__144$fn__165$fn__166$_inc__167$fn__168.invoke(clojure.clj)
    在logic.clj的211行clojure.core.logic.Substitutions.bind(invoke)
    在core.clj的58行rl.core$glyph_$fn__123$fn__144$fn__165$fn__166$_inc__167.invoke(invoke)
    在logic.clj的1160行clojure.core.logic$fn__1056$_inc__1057.invoke(invoke)
    在logic.clj的1160行clojure.core.logic$fn__1056$_inc__1057.invoke(invoke)
    在logic.clj的823行clojure.core.logic$fn__898$_inc__899.invoke(invoke)
    在logic.clj的828行clojure.core.logic$fn__890$fn__891.invoke(invoke)


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


异常在“main”线程 java.lang.ClassCastException: clojure.core.logic.LVar无法转换为clojure.lang.IFn
    在core.clj的67行rl.core$drawable_$fn__235$fn__248$fn__249$_inc__250$fn__251.invoke(invoke)
    在logic.clj的211行clojure.core.logic.Substitutions.bind(invoke)
    在core.clj的65行rl.core$drawable_$fn__235$fn__248$fn__249$_inc__250.invoke(invoke)
    在logic.clj的1160行clojure.core.logic$fn__1056$_inc__1057.invoke(invoke)
    在logic.clj的826行clojure.core.logic$fn__894$_inc__895.invoke(invoke)
    在logic.clj的1160行clojure.core.logic$fn__1056$_inc__1057.invoke(invoke)
    在logic.clj的823行clojure.core.logic$fn__898$_inc__899.invoke(invoke)
    在logic.clj的823行clojure.core.logic$fn__898$_inc__899.invoke(invoke)
    在logic.clj的823行clojure.core.logic$fn__898$_inc__899.invoke(invoke)
    在logic.clj的828行clojure.core.logic$fn__890$fn__891.invoke(invoke)


以下是一些参考信息(不要理会多余的方括号,由于需要在时间数据库中维护事实身份的便利性,我有一个奇怪的关键字/值问题)

(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) ...) 形式,这正是我不希望在这个情况下看到的东西。

我真心不知道为什么这里不工作,而match测试用例却可以。

0

评论者:dnolen

[(type-enum :dragon)]

这个模式看起来像你要匹配

[[:type :dragon]]

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

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

0

评论者:joeosborn

是的,这正是在这个情况下我所期望的结果--一个有标签的值。它失败的原因是什么,而:1230的测试用例没有失败,是因为它返回的是一个向量而不是一个列表?将函数返回类型从向量更改为列表似乎没有帮助。

我的补丁,供参考,没有表现出这种行为(至少对于宏,还没有测试过函数)。

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