请在 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行。

所以这应该可以正常工作,不需要显式支持宏,至少就我能看出是这样的。如果不是,那就可能是存在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
    在logic.clj第211行clojure.core.logic.Substitutions.bind
    在core.clj第58行rl.core$glyph_$fn__123$fn__144$fn__165$fn__166$_inc__167.invoke
    在logic.clj第1160行clojure.core.logic$fn__1056$_inc__1057.invoke
    在logic.clj第1160行clojure.core.logic$fn__1056$_inc__1057.invoke
    在logic.clj第823行clojure.core.logic$fn__898$_inc__899.invoke
    在logic.clj第828行clojure.core.logic$fn__890$fn__891.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
    在logic.clj第211行clojure.core.logic.Substitutions.bind
    在core.clj第65行rl.core$drawable_$fn__235$fn__248$fn__249$_inc__250.invoke
    在logic.clj第1160行clojure.core.logic$fn__1056$_inc__1057.invoke
    在logic.clj第826行clojure.core.logic$fn__894$_inc__895.invoke
    在logic.clj第1160行clojure.core.logic$fn__1056$_inc__1057.invoke
    在logic.clj第823行clojure.core.logic$fn__898$_inc__899.invoke
    在logic.clj第823行clojure.core.logic$fn__898$_inc__899.invoke
    在logic.clj第823行clojure.core.logic$fn__898$_inc__899.invoke
    在logic.clj第828行clojure.core.logic$fn__890$fn__891.invoke


以下是用于参考的 (glyph-) (不要介意所有的额外 [], 我因为某个有利于在时态数据库中维持事实的延续性而采用了奇怪的键/值对方式)

(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])


type-enum 作为函数定义

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

我不太确定为什么这在这里不工作,而在 matche 测试用例中工作。

0

评论者:dnolen

[(type-enum :dragon)]

这个模式似乎表明您想要匹配

[[:type :dragon]]

这里有一个额外的括号层级。这是否正确?

即便如此,我同意展开看起来不是很正确。我们绝不应该下降到一个那样的序列形式。

0

评论者:joeosborn

是的,这正是在这个情况下我希望得到的结果——在我的朴素的解释中,一个带有标签的值。它失败的真正原因而不是在 :1230 上的测试的原因是由于它产生了一个向量而不是列表吗?将 fn 的返回类型从向量更改为列表似乎并没有帮助。

我的补丁(仅供参考),并没有表现出这种行为(至少对于宏来说,还没有测试它是否与 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_

不是的!我确实想两者都要。我正在做一些关于时序逻辑的工作,我希望有一些方便的“更新”流量的方法,所以我想要区分参数的“键部分”和“值部分”。对于没有“值部分”的事实看起来有点傻,但它让我能够写出类似于以下这样的过程和函数:


(defrel heldo 时间 流量)
(defrel ¬heldo 时间 流量)
(declare fluent-obtainedo) ; 最近一次的 'held' 不是由 '¬held' 结束的,或者失败
(defn alter-fluent [时间 关系 键 新值]
  ;待办:错误检查,确保旧值不等于新值,旧值获得,新值未获得
  (doseq [旧值 (run* [旧值] (fluent-obtainedo 时间 [关系 键 旧值]))]
    (fact ¬heldo 时间 [关系 键 旧值]))
  (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 报告)
...