Commit 586439048bae69d0f6e3da5e0bdbb4ac10cda3d5

Thomas de Grivel 2023-06-25T15:25:50

work on negative bindings

diff --git a/README.md b/README.md
index 72bbe19..4d5b4ea 100644
--- a/README.md
+++ b/README.md
@@ -54,51 +54,69 @@ Adds facts (triples) to the database. Triples can be grouped by subject.
 The second version with `?movie` will generate an anonymous symbol prefixed with `movie-`.
 It is considered a more clean and efficient way to abstract identifiers.
 
+
 ### FACTS:RM &rest SPECS
+
 ```common-lisp
 (facts:rm (?movie :actor "Harison Ford"))
 ```
 
+
 ### FACTS:WITH SPECS &body BODY
 
 To follow Wittgenstein's view of the world, all queries get turned into
 testing the presence or absence of triples (facts).
 
+Variables are prefixed with a question mark symbol "?" and are
+wildcards, matching everything. Nested queries get their variables
+expanded, giving pattern matching abilities. For instance :
+
 ```common-lisp
-(defun movie-title (movie)
-  (facts:with ((movie :is-a :movie
-                      :title ?title)
-               (:not movie :is-a :fake))
-    (return ?title)))
+(with ((?s ?p ?o)
+  (format t "~&~S ~S ~S~&" ?s ?p ?o))
+
+=>
+"Blade Runner" :ACTOR "Harison Ford"
+"Blade Runner" :ACTOR "Rutger Hauer"
+"Blade Runner" :DIRECTOR "Ridley Scott"
+"Blade Runner" :IS-A :MOVIE
+"Snow White" :DIRECTOR "David Hand"
+"Snow White" :DIRECTOR "William Cottrell"
+"Snow White" :IS-A :MOVIE
 ```
 
-is equivalent to
+Multiple queries on the same subject can be grouped together easily :
 
 ```common-lisp
-(defun movie-title (movie)
-  (facts:with ((movie :is-a :movie)
-               (movie :title ?title)
-               (:not movie :is-a :fake))
-    (return ?title)))
+(facts:with ((?movie :is-a :movie
+                     :title ?title
+                     :director ?director))
+  (format t "~A directed ~A~%" ?director ?title))
 ```
 
-which is itself equivalent to
+Negative facts specifications will remove matching facts from the
+results.
+
 
 ```common-lisp
-(defun movie-title (movie)
-  (facts:with ((movie :is-a :movie))
-    (facts:with ((movie :title ?title))
-      (facts:without ((movie :is-a :fake))
-        (return ?title)))))
+(with ((?s ?p ?o)
+       (:not ?s :actor "Harison Ford"))
+  (format t "~&~S ~S ~S~&" ?s ?p ?o))
+
+=>
+"Snow White" :DIRECTOR "David Hand"
+"Snow White" :DIRECTOR "William Cottrell"
+"Snow White" :IS-A :MOVIE
 ```
 
-Multiple queries on the same subject can be grouped together easily :
 
-```common-lisp
-(facts:with ((?movie :is-a :movie
-                     :title ?title
-                     :director ?director))
-  (format t "~A directed ~A~%" ?director ?title))
+TODO
+----
+
+ - binding of negation : :not resulting from another binding
+ - barriers / hooks : functions that will be called when a spec is added
+   or removed.
+
 ```
 
 ### FACTS:\*DB\*
diff --git a/with.lisp b/with.lisp
index eddb89a..2d1898c 100644
--- a/with.lisp
+++ b/with.lisp
@@ -78,8 +78,9 @@
       ((3) (destructuring-bind (s p o) spec
              (with/dispatch s p o binding-vars body)))
       ((4) (destructuring-bind (not s p o) spec
-             (assert (eq :not not))
-             `(without ((,s ,p ,o)) ,@body))))))
+             (if (eq :not not)
+                 `(without ((,s ,p ,o)) ,@body)
+                 (with/dispatch s p o binding-vars body)))))))
 
 (defmacro with/rec ((spec &rest more-specs) &body body)
   (let* ((bindings (collect-bindings spec))