^7c6x970 # Dev Log 2022-07-09 ## ๐Ÿ… 1 - 10:05 Working on [[BOOK - Paradigms of Artificial Intelligence Programming - Peter Norvig]] chapter 11. Continuing work by writing some tests for VARIABLES-IN, and looking up ## ๐Ÿ… 2 - 10:30 Spent some time tracking down a computable copy of [[Common Lisp Hyperspec]], and wrote up some notes about [[IDEA - Common Lisp Hyperspec TailWind Modern site 1]] and [[Markdoc]]. Back to VARIABLES-IN, and looking up what ADJOIN does. It seems to basically be cons, but with uniqueness check. I'm trying to write a slightly more elaborate FIVEAM test, but it's not that easy to figure it out from the docs: ```lisp ;; rename variables (test (let ((vars (variables-in '(?x ?x ?y (?z ?z ?y (?x ?y)))))) (is (and (subsetp vars '(?x ?y ?z)) (subsetp '(?x ?y ?z) vars))))) ``` this fails with some macro error: ```lisp ; ; caught ERROR: ; (during macroexpansion of (DEF-TEST LET ; ...)) ; Error while parsing arguments to DEF-TEST DEFMACRO: ; unknown keyword: ((VARS ; (VARIABLES-IN ; '(?X ?X ?Y ; (?Z ?Z ?Y ; (?X ; ?Y)))))); expected one of :DEPENDS-ON, :SUITE, :FIXTURE, :COMPILE-AT, :PROFILE ; ``` So one thing, you can add multiple IS forms to a single test, as seen in the one example file I could find: - [fiveam/example.lisp at master ยท lispci/fiveam ยท GitHub](https://github.com/lispci/fiveam/blob/master/t/example.lisp) ```lisp ;;;; we create a test named ADD-2 and supply a short description. (test add-2 "Test the ADD-2 function" ;; a short description ;; the checks (is (= 2 (add-2 0))) (is (= 0 (add-2 -2)))) ``` ## ๐Ÿ…3 - 11:01 Well, turns out I was just being stupid and forgot to pass in the name of the test. The LET with nested IS works just fine. ```lisp ;; rename variables (test variables-in-complex "Test some more complex nested, repeated variables." (let ((vars (logic::variables-in '(?x ?x ?y (?z ?z ?y (?x ?y)))))) (is (and (subsetp vars '(?x ?y ?z)) (subsetp '(?x ?y ?z) vars))))) ``` ### Learning about sly-stickers Set a sticker with `C-c C-s C-s` (this is the DWIM command, so you can use it to remove stickers as well). In general the command is `SPC m s` followed by the command. `SPC m` is the shortcut for the mode commands, I guess. You then need to compile the form again with `C-c C-c` or `C-c C-k` (compile file). Armed stickers are then blue. Inspect recorded stickers with `C-c C-s C-r` (`sly-stickers-replay`). You can clear all stickers with `C-c C-s F` (no SPC m binding, because I guess it's not C-F). ### ๐Ÿ… 4 - 11:25 ### Learning about SLY-DB I want to examine the goals and stickers as I step through GOALS. This could be a cool little thing for a video tutorial / demonstration of the Prolog interpreter. Maybe start with a smaller example (just some tools in chapter 05, instead of a real system). Then move on to PAT-MATCH. t - toggle details of frame v - view frame source e - eval in frame d - evaluate and prettyprint I'm not fully clear how to set breakpoint. Can you only do it through break on stickers? Sly-db-break seems not implemented. So how to I break on function entry. I guess adding an explicit call to `(BREAK)` is the way to go? SO it looks like the stickers were messing with my stack frame when placing a breakpoint in a lambda: ```lisp (defun prove (goal bindings) "Return a list of possible solutions to GOAL." (break) (mapcan #'(lambda (clause) ;; for each clause, rename the variables to be unique, ;; because we need to distinguish ?x in one clause from ?x in another clause (let ((new-clause (rename-variables clause))) (print new-clause) (print clause) (break) (prove-all (clause-body new-clause) (unify goal (clause-head new-clause) bindings)))) ;; we get all the clauses that match the predicate of our goal (get-clauses (predicate goal)))) ``` The frame of the breakpoint inside the lambda would not evaluate NEW-CLAUSE or CLAUSE. After removing the stickers, at least I get NEW-CLAUSE (but not CLAUSE? this might maybe be due to SBCL?). See [Variable Value Availability](http://www.sbcl.org/manual/#Variable-Value-Availability) in the [[SBCL]] manual. . Let's try fresh. ## ๐Ÿ… 5 - 15:21 Continuing on chapter 11, now that I know a bit more about the debugger. Another option for visualizing this is to just capture the steps and output a graph, for example. For example with optional compilation. Prolog searches for solutions in a top-down, left-to-right fashion. The clauses are searched from the top down. I am now getting into the backtracking part. Currently, all answers are computed as batch, but really we want an incremental approach where each vaue is computed, and the user is then given the option to continue. This will allow it to handle infinite results, and work depth search, so saving on memory (because it can forget previous results). The prolog interpreter in SICP uses delayed computation using thunks (or streams or pipes...). The first step is a version of prove and prove-all that only returns one value. Apparently, this is what is being done in GPS as well, except that GPS checks recursive subgoals and clobbered sibling goals. I don't know what that means, so at some point it would be interesting to go back to GPS. ## ๐Ÿ… 6 - 15:54 PROVE has to go through all the solutions systematically, so we pass it the list of GOALS to try after the current one. It seems I have a bug here, on page 371, ```list (?- (length ?l (1+ (1+ 0))) (member a ?l)) ;; should return ?l = (a ?x) ?l = (?y a) No. ``` but that doesn't seem to be the case. I do get (a ?x) and (a a) as results. ## ๐Ÿ…7 - 16:21 Tracing the calls to UNIFY, PROVE and PROVE-ALL, we can see UNIFY finding a solution for (LENGTH ?L (1+ (1+ 0))) ```lisp 4: UNIFY returned ((#:?N1448 . 0) (#:?Y1444 #:?X1446 . #:?Y1447) (#:?N1445 1+ 0) (?L #:?X1443 . #:?Y1444)) ``` We can then see the move to the next goal MEMBER: ``` 6: (LOGIC::PROVE-ALL ((MEMBER LOGIC::A LOGIC::?L) (LOGIC::SHOW-PROLOG-VARS LOGIC::?L)) ((#:?Y1447) (#:?N1448 . 0) (#:?Y1444 #:?X1446 . #:?Y1447) (#:?N1445 1+ 0) (LOGIC::?L #:?X1443 . #:?Y1444))) ``` - [x] NEXT STEPS โœ… 2023-08-05 Next steps: - use conditional compilation to add methods to trace - UNIFY (print out the bound variables in the expression to unify, print out the environment) - Do the same when proving a single goal