如何在Clojure的Clara Rules中更新事实?
问题分析与解决方案
你的代码问题点
你提供的代码存在几个语法/用法错误,这是导致规则不工作的直接原因:
defrecord UserData定义末尾缺少闭合括号)- 规则中的箭头符号用了HTML转义的
</>,需替换为Clara支持的</> - 规则右侧操作(RHS)写法错误:你把
retract!和insert!包在双重括号里,这会导致尝试调用retract!的返回值作为函数,正确做法是用do块包裹多个操作(或直接换行利用Clojure隐式do) run-rules函数最后没有返回会话结果,无法获取更新后的状态
修正后的代码
(ns clara.rules.test (:require [clara.rules :refer :all])) ;; 补全UserData定义的闭合括号 (defrecord Users [#^ints user-ids]) (defrecord UserData [user-id dob age]) (defrule rule-1 ;; 替换转义符号为正确的箭头 [?ud <- UserData (> age 20)] [?u <- Users] => ;; 用do块执行多个操作,去掉多余括号 (do (retract! ?u) (insert! (->Users (conj (:user-ids ?u) (:user-id ?ud)))))) ;; 保留自定义条件占位,实际使用时需实现some-condition逻辑 (defrule rule-2 [?ud <- UserData (some-condition)] [?u <- Users] => (do (retract! ?u) (insert! (->Users (conj (:user-ids ?u) (:user-id ?ud)))))) (defn run-rules [user-data] (let [res (-> (mk-session 'clara.rules.test) (insert (->UserData (:user-id user-data) (:dob user-data) (:age user-data)) (->Users [])) (fire-rules))] ;; 返回会话,方便后续提取更新后的事实 res))
核心问题解答
Clara Rules不支持直接更新现有事实,官方推荐的做法就是你尝试的「撤回旧事实 + 插入新事实」模式,这是规则引擎中处理状态更新的标准方式。
使用时需注意几个关键点:
- 确保撤回的事实与插入的新事实是逻辑上的同一份状态,避免出现重复的Users事实
- 若多个规则可能修改Users事实,可通过
:salience参数调整规则触发优先级(默认按定义顺序触发) - 可通过查询验证更新结果,比如添加以下查询函数:
(defquery get-users [] [?u <- Users]) ;; 使用示例 (let [session (run-rules {:user-id 1 :dob "1999-01-01" :age 25})] (query session get-users))
内容的提问来源于stack exchange,提问作者xyj
相关产品推荐
相关产品推荐

