clara-rulesのセッションの中身を外から調べるためのクエリ機能があるので使い方を調べてみた。
- 基本的にはルールの左辺だけを定義する。
ルールとの役割の違い
- ルールはセッションに追加された既存のファクトから新しいファクトを導き出すために使う
- クエリは純粋にセッションの中を調べるために使う
- デバッグ
- 計算が終わったセッションから情報を取り出し、別の処理に渡すための中間ステップ
コード例
(ns clara-rules.join
(:require [clara.rules :refer [defrule fire-rules insert
mk-session query defquery]]))
(defrecord TypeA [attr-a join-key])
(defrecord TypeB [attr-b join-key])
;;Queries
(defquery find-all-As
[];;parameters
[?a <- TypeA];;Matching condition
)
(defquery find-As-by-attr
[:?value];; Parameter needs to be a keyword
[?a <- TypeA (= attr-a ?value)])
(defquery find-join-key-of-As
[]
[TypeA (= ?jk join-key)])
(defquery find-A-and-B-pair-by-join-key
[:?value]
[?a <- TypeA (= join-key ?value)]
[?b <- TypeB (= join-key ?value)])
(def sess (-> (mk-session)
(insert (->TypeA "a1" :foo)
(->TypeA "a2" :bar)
(->TypeA "a3" :baz)
(->TypeB "b1" :foo)
(->TypeB "b2" :bar)
(->TypeB "b3" :baz)
(->TypeB "b4" :qux))
(fire-rules)))
(query sess find-all-As)
;; ({:?a {:attr-a "a1", :join-key :foo}}
;; {:?a {:attr-a "a2", :join-key :bar}}
;; {:?a {:attr-a "a3", :join-key :baz}})
(query sess find-As-by-attr :?value "a1")
;; => ({:?a #clara_rules.join.TypeA{:attr-a "a1", :join-key :foo}, :?value "a1"})
(query sess find-join-key-of-As)
;; => ({:?jk :foo} {:?jk :bar} {:?jk :baz})
(query sess find-A-and-B-pair-by-join-key :?value :foo)
;; => ({:?a {:attr-a "a1", :join-key :foo},
;; :?value :foo,
;; :?b {:attr-b "b1", :join-key :foo}})
上記コードの注目点
-
defquery
はパラメターを外部受けとることができること以外は、defrule
の左辺と同じ様に書ける- 変数の束縛etc
-
query
はdefquery
内で束縛された変数を結果のマップのキーとして返す -
query
はマッチした物をマップのシークエンスとして返す
感想
以前までの例では結果を確認するためにはルールの右辺で副作用を(println)用いる事しかしていなかった。
副作用を用いずに結果を確認する手段が無いものかと触った時から抱いていた疑問が一つ解けたので嬉しい。