Last active
December 10, 2021 16:17
-
-
Save cgrand/18b7b0fdceb0b5a20b285df3b8bd9b07 to your computer and use it in GitHub Desktop.
Putting expressions in datomic-flavored datalog :where clauses. (This is a snippet I had laying around and that I'd like to develop further.)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns tensegritics.expressive.datalog | |
"Putting expressions in datomic-flavored datalog :where clauses.") | |
;; I (cgrand) believes that datalog literally lacks expressivity because | |
;; it's not expression-based but clause-based and thus requires a lot of | |
;; gratuitous naming. | |
;; Here is an attempt to compiles expressions into clauses. | |
(defn- grounded? [[e a v]] (and (keyword? a) (not (symbol? v)))) | |
(defn- unravel [x] | |
(cond | |
(not (coll? x)) | |
[[x]] | |
(map? x) | |
(let [id (or (:db/id x) (gensym '?eid)) | |
x (dissoc x :db/id)] | |
[[id] | |
(let [[front back] | |
(reduce-kv | |
(fn [[front back] a v] | |
(let [mk-clause | |
(if (and (keyword? a) (.startsWith (name a) "_")) | |
(let [a (keyword (namespace a) (subs (name a) 1))] | |
(fn [v] [v a id])) | |
(fn [v] [id a v])) | |
[vals clauses] (unravel v)] | |
[(into front (map mk-clause) vals) | |
(into back clauses)])) | |
[[] []] | |
x)] | |
(-> [] | |
(into (filter grounded?) front) | |
(into (remove grounded?) front) | |
(into back)))]) | |
(vector? x) | |
(let [x (map unravel x)] | |
[(mapcat first x) (mapcat second x)]) :else | |
(throw (ex-info "Can't unravel this expression")))) | |
(defn where | |
"Takes an expr (generally a map) and flatten it into a coll of clauses." | |
[expr] (second (unravel expr))) | |
(comment | |
; this: | |
(where '#:game | |
{:teams #:team | |
{:players #:player{:name ?pid} | |
:final-score ?ts} | |
:date ?d}) | |
; returns: | |
[[?eid7207 :game/teams ?eid7208] | |
[?eid7207 :game/date ?d] | |
[?eid7208 :team/players ?eid7209] | |
[?eid7208 :team/final-score ?ts] | |
[?eid7209 :player/name ?pid]] | |
; or this one: | |
(where '#:artist | |
{:name ?artist-name | |
:release/_artists #:release {:name ?release-name}}) | |
; returns: | |
[[?eid7213 :artist/name ?artist-name] | |
[?eid7214 :release/artists ?eid7213] | |
[?eid7214 :release/name ?release-name]]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment