Java
JavaScript
Clojure
ClojureScript
clara-rules

前回

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
  • querydefquery内で束縛された変数を結果のマップのキーとして返す
  • queryはマッチした物をマップのシークエンスとして返す

感想

以前までの例では結果を確認するためにはルールの右辺で副作用を(println)用いる事しかしていなかった。
副作用を用いずに結果を確認する手段が無いものかと触った時から抱いていた疑問が一つ解けたので嬉しい。

次回