update content
[arxana.git] / latex / arxana-merge.tex
blob6fcbda018169509fe661bcb5dc13e57a1a179434
1 %;; Copyright (C) 2005-2017 Joe Corneli <holtzermann17@gmail.com>
2 %;; Copyright (C) 2010-2017 Ray Puzio <rsp@novres.org>
4 %;; This program is free software: you can redistribute it and/or modify
5 %;; it under the terms of the GNU Affero General Public License as published by
6 %;; the Free Software Foundation, either version 3 of the License, or
7 %;; (at your option) any later version.
8 %;;
9 %;; This program is distributed in the hope that it will be useful,
10 %;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 %;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 %;; GNU Affero General Public License for more details.
13 %;;
14 %;; You should have received a copy of the GNU Affero General Public License
15 %;; along with this program. If not, see <http://www.gnu.org/licenses/>.
17 %% (defun load-arxana ()
18 %% (interactive)
19 %% (find-file "~/arxana/latex/arxana-merge.tex")
20 %% (save-excursion
21 %% (goto-char (point-max))
22 %% (let ((beg (progn (search-backward "\\begin{verbatim}")
23 %% (match-end 0)))
24 %% (end (progn (search-forward "\\end{verbatim}")
25 %% (match-beginning 0))))
26 %% (eval-region beg end)
27 %% (lit-eval)
28 %% (autoimport-arxana)
29 %% (pick-a-name))))
31 %%% Commentary:
33 %% To load: remove %'s above and evaluate with C-x C-e, then run M-x load-arxana RET
35 %% Alternatively, run this:
36 % head -n 29 arxana-merge.tex | sed -e "/%* \{0,1\}/s///" > arxana-loader.el
37 %% on the command line to produce something you can use
38 %% to load Arxana when you start Emacs:
39 % emacs -l arxana-loader.el
41 %% Or put the expression in your ~/.emacs
43 %% Or search for a similar form below and evaluate there!
45 %%% Code:
47 \documentclass{article}
48 %\usepackage{showframe}
50 \usepackage[T1]{fontenc}
51 \usepackage{textcomp}
53 \usepackage{hyperref}
54 \usepackage{amsmath}
55 \usepackage{amsthm}
56 \usepackage{verbatim}
58 \usepackage{makeidx}
59 \makeindex
60 \usepackage{idxlayout}
62 \newcommand{\todo}[1]{\footnote{\bf TODO: #1}}
63 \newcommand{\meta}[1]{$\langle${\it #1}$\rangle$}
65 \theoremstyle{definition}
66 \newtheorem{nota}{Note}[section]
68 \parindent = 1.2em
70 \newenvironment{notate}[1]
71 {\index{#1}%
72 \begin{nota}[{\bf {\em #1}}]}%
73 {\end{nota}}
75 \makeatletter
76 \newenvironment{elisp}
77 {\let\ORGverbatim@font\verbatim@font
78 \def\verbatim@font{\ttfamily\scshape}%
79 \verbatim}
80 {\endverbatim
81 \let\verbatim@font\ORGverbatim@font}
82 \makeatother
84 \makeatletter
85 \newenvironment{idea}
86 {\let\ORGverbatim@font\verbatim@font
87 \def\verbatim@font{\ttfamily\slshape}%
88 \verbatim}
89 {\endverbatim
90 \let\verbatim@font\ORGverbatim@font}
91 \makeatother
93 \usepackage{newverbs}
94 \newcommand{\verbal}{\collectverb{\scshape}}
96 \begin{document}
98 \title{\emph{Arxana 2017}}
100 \author{Joseph Corneli \& Raymond Puzio\thanks{Copyright (C) 2005-2017
101 Joseph Corneli {\tt <holtzermann17@gmail.com>}\newline
102 Copyright (C) 2010-2017 Raymond Puzio {\tt <rsp@novres.org>}\newline
103 $\longrightarrow$ transferred to the public domain.}}
104 \date{Last revised: \today}
106 \maketitle
108 \abstract{A tool for building hackable semantic hypertext platforms.
109 An overview and link to our source code repository is at {\tt
110 http://arxana.net}.}
112 \tableofcontents
114 \section{Introduction}
116 \begin{notate}{What is ``Arxana''?} \label{arxana}
117 \emph{Arxana} is the name of a ``next generation'' hypertext system
118 that emphasizes annotation. Every object in this system is
119 annotatable. Because of this, our first name for the program ``the
120 scholium system'', but ``Arxana'' better reflects our aim: to explore
121 the mysterious world of links, attachments, correspondences, and
122 side-effects. This edition of the program relies entirely on Emacs
123 for storage and display, and integrates a backend storage mechanism
124 devised by Ray Puzio, and frontend interactions from earlier
125 prototypes by Joe Corneli, and (in Section \ref{farm-demo}) a new
126 application to modelling mathematical dialogues jointly developed by
127 both authors. Previous versions contain often excessive but
128 sometimes interesting discussion of ideas for future work.
129 Such discussion has been kept to a minimum here.
130 \end{notate}
132 \begin{notate}{Using the program}
133 If you are looking at the source version of this document
134 in Emacs, evaluate the following s-expression (type
135 \emph{C-x C-e} with the cursor positioned just after its
136 final parenthesis). This prepares the Emacs environment
137 for interactive use. (The code that achieves this is
138 in Appendix \ref{appendix-lit}.)
140 \begin{idea}
141 (save-excursion
142 (let ((beg (search-forward "\\begin{verbatim}"))
143 (end (progn (search-forward "\\end{verbatim}")
144 (match-beginning 0))))
145 (eval-region beg end)
146 (lit-process)))
147 \end{idea}
149 If you are looking at this in a PDF or printout, you will see that the
150 document has a ``literate'' style. That is, it can be read as text,
151 not just as code. In Section \ref{frontend}, we define functions that
152 allow the user to read and revise the contents of this document as
153 hypertext.
154 \end{notate}
156 \section{Backend}
158 \begin{notate}{Overview of the backend}
159 This backend is a Higher Order NEtwork Yarnknotter or HONEY for short.
160 It stores a \emph{network} of quintuplets of the form {\tt(uid label
161 source sink . content)}. One such quintuplet is called a
162 \emph{nema}. The structure of an individual nema is as follows: The
163 {\tt uid} is a numeric identifier that is unique on a network
164 basis. The {\tt label} is an (optional) string that corresponds
165 uniquely to the uid. The {\tt source} is the nema (identified by
166 uid) to the ``left'' of our quintuplet, and the {\tt sink} is the
167 uid to the ``right'' of our quintuplet. One or both may be {\tt
168 0}, and in case both are, the nema is understood to be a
169 \emph{node}. Lastly, the nema's {\tt content} can be any Lisp
170 object -- including another nema in the same network or another
171 network.\todo{(Check this last statement...)}
172 \end{notate}
174 \subsection{Preliminaries}
176 \begin{notate}{Some preliminaries}
177 We define several simple preliminary functions that we use later on.
178 \end{notate}
180 \begin{notate}{Required packages}
181 We use the Common Lisp compatibility functions.
182 \end{notate}
184 \begin{elisp}
185 (require 'cl)
186 \end{elisp}
188 \begin{notate}{On `filter'}
189 This is a useful utility to filter elements of a list satisfying a condition.
190 Returns the subset of stuff which satisfies the predicate pred.
191 \end{notate}
193 \begin{elisp}
194 (defun filter (pred stuff)
195 (let ((ans nil))
196 (dolist (item stuff (reverse ans))
197 (if (funcall pred item)
198 (setq ans (cons item ans))
199 nil))))
200 \end{elisp}
202 \begin{idea}
203 (filter '(lambda (x) (= (% x 2) 1)) '(1 2 3 4 5 6 7))
204 => (1 3 5 7)
205 \end{idea}
207 \begin{notate}{On `intersection'}
208 Set-theoretic intersection operation. More general than the version
209 coming from the `cl' package.
210 \end{notate}
212 \begin{elisp}
213 (defun intersection (&rest arg)
214 (cond ((null arg) nil)
215 ((null (cdr arg)) (car arg))
216 (t (let ((ans nil))
217 (dolist (elmt (car arg) ans)
218 (let ((remainder (cdr arg)))
219 (while (and remainder
220 (member elmt (car remainder)))
221 (setq remainder (cdr remainder))
222 (when (null remainder)
223 (setq ans (cons elmt ans))))))))))
224 \end{elisp}
226 \begin{idea}
227 (intersection '(a b c d e f g h j)
228 '(a b h j k)
229 '(b d g h j k))
230 => (j h b)
231 \end{idea}
233 \begin{notate}{On `mapply'}
234 Map and apply rolled into one.
235 \end{notate}
236 \begin{elisp}
237 (defun mapply (f l)
238 (if (member nil l) nil
239 (cons (apply f (mapcar 'car l))
240 (mapply f (mapcar 'cdr l)))))
241 \end{elisp}
243 \begin{idea}
244 (mapply '+ '((1 2) (3 4)))
245 => (4 6)
246 \end{idea}
248 \begin{notate}{On `sublis'}
249 Substitute objects in a list.
250 \end{notate}
252 \begin{elisp}
253 (defun sublis (sub lis)
254 (cond
255 ((null lis) nil)
256 ((assoc lis sub) (cadr (assoc lis sub)))
257 ((atom lis) lis)
258 (t (cons (sublis sub (car lis))
259 (sublis sub (cdr lis))))))
260 \end{elisp}
262 \subsection{Core definitions}
264 \begin{notate}{HONEY set up}
265 These variables are needed for a coherent set-up.\todo{Explain
266 what they will do.}
267 \end{notate}
269 \begin{elisp}
270 (defvar plexus-registry '(0 nil))
271 (defvar current-plexus nil)
272 \end{elisp}
274 \begin{notate}{The `add-plexus' function} \label{the-new-net-function}
275 We use this create a new plexus for storage. It defines a
276 counter (beginning at 1), together with several hash tables that allow
277 efficient access to the plexus' contents: an article table, forward
278 links, backward links, forward labels, and backward labels.
279 Additionally, it defines a ``ground'' and
280 ``type'' nodes.\todo{Explain these things in more detail.}\todo{NB. it could be useful
281 to maintain a registry available networks, by analogy with
282 Emacs's `buffer-list', which
283 I think could be done if we use `cl-defstruct' below
284 instead of `list', and set up the constructor suitably
285 (info \textquotedbl(cl) Structures\textquotedbl).}
286 \end{notate}
288 \begin{elisp}
289 (defun add-plexus ()
290 "Create a new plexus."
291 (let ((newbie (list '*plexus*
292 1 ; nema counter
293 (make-hash-table :test 'equal) ; nema table
294 (make-hash-table :test 'equal) ; forward links
295 (make-hash-table :test 'equal) ; backward links
296 (make-hash-table :test 'equal) ; forward labels
297 (make-hash-table :test 'equal) ; backward labels
298 (car plexus-registry))))
299 ;; Define ground and type nodes.
300 (puthash 0 '(0 0) (nth 2 newbie))
301 (puthash 1 '(0 0) (nth 2 newbie))
302 (puthash 0 '((0 . 0) (1 . 0)) (nth 3 newbie))
303 (puthash 0 '((0 . 0) (1 . 0)) (nth 4 newbie))
304 (puthash 0 '"ground" (nth 5 newbie))
305 (puthash '"ground" 0 (nth 6 newbie))
306 (puthash 1 '"type" (nth 5 newbie))
307 (puthash '"type" 1 (nth 6 newbie))
308 ;; Register the new object and return it.
309 (setq plexus-registry
310 (append
311 `(,(+ (car plexus-registry) 1)
312 ,newbie)
313 (cdr plexus-registry)))
314 newbie))
315 \end{elisp}
317 \begin{notate}{The ``remove-plexus'' function}
318 When we're done with our plexus, we should tidy up after ourselves.
319 \end{notate}
321 \begin{elisp}
322 (defun remove-plexus (plex)
323 "Remove a plexus."
324 ;; Wipe out the hash tables
325 (dotimes (i 5)
326 (clrhash (nth (+ i 2) plex)))
327 ;; Remove the entry from the registry.
328 (setq plexus-registry
329 (cons
330 (car plexus-registry)
331 (delete
332 (assoc (nth 7 plex)
333 (cdr plexus-registry))
334 (cdr plexus-registry)))))
335 \end{elisp}
337 \begin{elisp}
338 (defun show-plexus-registry ()
339 plexus-registry)
340 \end{elisp}
342 \begin{notate}{Network selection}
343 We can work with several networks, only one of
344 which is ``current'' at any given time.
345 \end{notate}
347 \begin{elisp}
348 (defun set-current-plexus (plex)
349 "Examine a different plexus instead."
350 (setq current-plexus plex))
352 (defmacro with-current-plexus (plex &rest expr)
353 (declare (debug (&rest form)))
354 (append `(let ((current-plexus ,plex))) expr))
356 (defun show-current-plexus ()
357 "Return the plexus currently being examined."
358 current-plexus)
359 \end{elisp}
361 \begin{notate}{On `next-unique-id'}
362 Increment the identifier that tells us how many nemas are in our network.
363 \end{notate}
365 \begin{elisp}
366 (defun next-unique-id ()
367 "Produce a yet unused unique identifier."
368 (1+ (cadr current-plexus)))
369 \end{elisp}
371 \begin{notate}{On `reset-plexus'}
372 Reset article counter and hash tables. Redefine ``ground'' and
373 ``article-type''.
374 \end{notate}
376 \begin{elisp}
377 (defun reset-plexus ()
378 "Reset the database to its initial configuration."
379 ; Reset nema counter and hash tables.
380 (setcar (cdr current-plexus) 1)
381 (dotimes (n 5)
382 (clrhash (nth (+ n 2) current-plexus)))
383 ;; Define ground and nema-type.
384 (puthash 0 '(0 0) (nth 2 current-plexus))
385 (puthash 1 '(0 0) (nth 2 current-plexus))
386 (puthash 0 '((0 . 0) (1 . 0)) (nth 3 current-plexus))
387 (puthash 0 '((0 . 0) (1 . 0)) (nth 4 current-plexus))
388 (puthash 0 '"ground" (nth 5 current-plexus))
389 (puthash '"ground" 0 (nth 6 current-plexus))
390 (puthash 1 '"type" (nth 5 current-plexus))
391 (puthash '"type" 1 (nth 6 current-plexus))
392 nil)
393 \end{elisp}
395 \subsection{Individual Operations}
397 \begin{notate}{On `add-nema'}
398 Add record to article table.
399 Add record to list of forward links of source.
400 Add record to list of backward links of sink.
401 Return the id of the new article.\todo{Should we add an alias `add-triple'
402 for this function, to make it more clear that our middle/frontend
403 is not implementation specific?}
404 \end{notate}
406 \begin{elisp}
407 (defun add-nema (src txt snk)
408 "Enter a new nema to the database."
409 (let ((uid (next-unique-id)))
410 ;; Add record to nema table.
411 (puthash uid
412 `(,src ,snk . ,txt)
413 (nth 2 current-plexus))
414 ;; Add record to list of forward links of source.
415 (puthash src
416 (cons `(,uid . ,snk)
417 (gethash src (nth 3 current-plexus) nil))
418 (nth 3 current-plexus))
419 ;; Add record to list of backward links of sink.
420 (puthash snk
421 (cons
422 `(,uid . ,src)
423 (gethash snk (nth 4 current-plexus) nil))
424 (nth 4 current-plexus))
425 ;; Update the counter for long-term storage
426 (setcar (cdr current-plexus) uid)
427 ;; Return the id of the new nema.
428 uid))
429 \end{elisp}
431 \begin{notate}{Retrieving elements of a nema} \label{retrieving-elements}
432 These functions exist to get the relevant components
433 of a nema, given its uid.
434 \end{notate}
436 \begin{elisp}
437 (defun get-content (uid)
438 "Return the content of the nema."
439 (cddr (gethash uid (nth 2 current-plexus))))
441 (defun get-source (uid)
442 "Return the source of the nema."
443 (car (gethash uid (nth 2 current-plexus))))
445 (defun get-sink (uid)
446 "Return the sink of the nema."
447 (cadr (gethash uid (nth 2 current-plexus))))
449 (defun get-triple (uid)
450 (list (get-source uid)
451 (get-content uid)
452 (get-sink uid)))
453 \end{elisp}
455 \begin{notate}{On `update-content'}
456 old source
457 old sink
458 new content
459 \end{notate}
461 \begin{elisp}
462 (defun update-content (uid txt)
463 "Replace the content of the nema."
464 (puthash uid
465 (let ((x (gethash uid (nth 2 current-plexus))))
466 `(,(car x) ; old source
467 ,(cadr x) . ; old sink
468 ,txt)) ; new content
469 (nth 2 current-plexus)))
470 \end{elisp}
472 \begin{notate}{On `update-source'}
473 Extract current source.
474 Extract current sink.
475 Extract current content.
476 Update the entry in the article table.
477 Remove the entry with the old source in the
478 forward link table. If that is the only entry
479 filed under old-src, remove it from table.
480 Add an entry with the new source in the
481 forward link table.
482 Update the entry in the backward link table.
483 \end{notate}
485 \begin{elisp}
486 (defun update-source (uid new-src)
487 "Replace the source of the nema."
488 (let* ((x (gethash uid (nth 2 current-plexus)))
489 (old-src (car x)) ; extract current source
490 (old-snk (cadr x)) ; extract current sink
491 (old-txt (cddr x))) ; extract current content
492 ;; Update the entry in the nema table.
493 (puthash uid
494 `(,new-src ,old-snk . ,old-txt)
495 (nth 2 current-plexus))
496 ;; Remove the entry with the old source in the
497 ;; forward link table. If that is the only entry
498 ;; filed under old-src, remove it from table.
499 (let ((y (delete `(,uid . ,old-snk)
500 (gethash old-src
501 (nth 3 current-plexus)
502 nil))))
503 (if y
504 (puthash old-src y (nth 3 current-plexus))
505 (remhash old-src (nth 3 current-plexus))))
506 ;; Add an entry with the new source in the
507 ;; forward link table.
508 (puthash new-src
509 (cons `(,uid . ,old-snk)
510 (gethash old-src (nth 3 current-plexus) nil))
511 (nth 3 current-plexus))
512 ;; Update the entry in the backward link table.
513 (puthash old-snk
514 (cons `(,uid . ,new-src)
515 (delete `(,uid . ,old-src)
516 (gethash old-src
517 (nth 4 current-plexus)
518 nil)))
519 (nth 4 current-plexus))))
520 \end{elisp}
522 \begin{notate}{On `update-sink'} \label{update-sink}
523 Extract current source.
524 Extract current sink.
525 Extract current content.
526 Update the entry in the article table.
527 Remove the entry with the old sink in the
528 backward link table. If that is the only entry
529 filed under old-src, remove it from table.
530 Add an entry with the new source in the
531 backward link table.
532 Update the entry in the forward link table.
533 \end{notate}
535 \begin{elisp}
536 (defun update-sink (uid new-snk)
537 "Change the sink of the nema."
538 (let* ((x (gethash uid (nth 2 current-plexus)))
539 (old-src (car x)) ; extract current source
540 (old-snk (cadr x)) ; extract current sink
541 (old-txt (cddr x))) ; extract current content
542 ; Update the entry in the nema table.
543 (puthash uid
544 `(,old-src ,new-snk . ,old-txt)
545 (nth 2 current-plexus))
546 ;; Remove the entry with the old sink in the
547 ;; backward link table. If that is the only entry
548 ;; filed under old-src, remove it from table.
549 (let ((y (delete `(,uid . ,old-src)
550 (gethash old-snk
551 (nth 4 current-plexus)
552 nil))))
553 (if y
554 (puthash old-snk y (nth 4 current-plexus))
555 (remhash old-snk (nth 4 current-plexus))))
556 ;; Add an entry with the new source in the
557 ;; backward link table.
558 (puthash new-snk
559 (cons `(,uid . ,old-src)
560 (gethash old-snk
561 (nth 4 current-plexus)
562 nil))
563 (nth 4 current-plexus))
564 ;; Update the entry in the forward link table.
565 (puthash old-src
566 (cons `(,uid . ,new-snk)
567 (delete `(,uid . ,old-snk)
568 (gethash old-src
569 (nth 3 current-plexus)
570 nil)))
571 (nth 3 current-plexus))))
572 \end{elisp}
574 \begin{notate}{On `remove-nema'}
575 Remove forward link created by article.
576 Remove backward link created by article.
577 Remove record from article table.
578 \end{notate}
580 \begin{elisp}
581 (defun remove-nema (uid)
582 "Remove this nema from the database."
583 (let ((old-src (car (gethash uid (nth 2 current-plexus))))
584 (old-snk (cadr (gethash uid (nth 2 current-plexus)))))
585 ;; Remove forward link created by nema.
586 (let ((new-fwd (delete `(,uid . ,old-snk)
587 (gethash old-src (nth 3 current-plexus)))))
588 (if new-fwd
589 (puthash old-src new-fwd (nth 3 current-plexus))
590 (remhash old-src (nth 3 current-plexus))))
591 ;; Remove backward link created by nema.
592 (let ((new-bkw (delete `(,uid . ,old-src)
593 (gethash old-snk (nth 4 current-plexus)))))
594 (if new-bkw
595 (puthash old-snk new-bkw (nth 4 current-plexus))
596 (remhash old-snk (nth 4 current-plexus))))
597 ;; Remove record from nema table.
598 (remhash uid (nth 2 current-plexus))))
599 \end{elisp}
601 \begin{notate}{Functions for gathering links}
602 Links are stored on triples alongside other
603 elements.
604 \end{notate}
606 \begin{elisp}
607 (defun get-forward-links (uid)
608 "Return all links having given object as source."
609 (mapcar 'car (gethash uid (nth 3 current-plexus))))
611 (defun get-backward-links (uid)
612 "Return all links having given object as sink."
613 (mapcar 'car (gethash uid (nth 4 current-plexus))))
614 \end{elisp}
616 \begin{notate}{On `label-nema'}
617 Nemas can be given a unique human-readable label in addition
618 to their numeric uid.
619 \end{notate}
621 \begin{elisp}
622 (defun label-nema (uid label)
623 "Assign the label to the given object."
624 (puthash uid label (nth 5 current-plexus))
625 (puthash label uid (nth 6 current-plexus)))
626 \end{elisp}
628 \begin{notate}{Label to uid and uid to label lookup}
629 These functions allow the exchange of uid and label.
630 \end{notate}
632 \begin{elisp}
633 (defun label2uid (label)
634 "Return the unique identifier corresponding to a label."
635 (gethash label (nth 6 current-plexus) nil))
637 (defun uid2label (uid)
638 "Return the label associated to a unique identifier."
639 (gethash uid (nth 5 current-plexus) nil))
640 \end{elisp}
642 \subsection{Bulk Operations}
644 \begin{notate}{On `download-en-masse'}
645 Unpack triplets, obtain labels if they exist.
646 Write data in the network to a list, and return.
647 \end{notate}
649 \begin{elisp}
650 (defun download-en-masse ()
651 "Produce a representation of the database as quintuples."
652 (let ((plex nil))
653 (maphash (lambda (uid tplt)
654 ;; Unpack triplet.
655 (let ((src (car tplt))
656 (snk (nth 1 tplt))
657 (txt (nthcdr 2 tplt)))
658 ;; Obtain label if exists.
659 (setq lbl (gethash uid
660 (nth 5 current-plexus)
661 nil))
662 ;; Write data to list.
663 (setq plex (cons `(,uid ,lbl ,src ,snk . ,txt)
664 plex))))
665 (nth 2 current-plexus))
666 ;; Return list of data.
667 (reverse plex)))
668 \end{elisp}
670 \begin{notate}{On `upload-en-masse'}
671 Unpack quintuplets. Plug into tables.
672 Bump up article counter as needed.
673 \end{notate}
675 \begin{elisp}
676 (defun upload-en-masse (plex)
677 "Load a representation of a database as quintuples into memory."
678 (dolist (qplt plex t)
679 ; unpack quintuplet
680 (let ((uid (car qplt))
681 (lbl (nth 1 qplt))
682 (src (nth 2 qplt))
683 (snk (nth 3 qplt))
684 (txt (nthcdr 4 qplt)))
685 ; plug into tables
686 (puthash uid
687 `(,src ,snk . ,txt)
688 (nth 2 current-plexus))
689 (puthash src
690 (cons `(,uid . ,snk)
691 (gethash src (nth 3 current-plexus) nil))
692 (nth 3 current-plexus))
693 (puthash snk
694 (cons
695 `(,uid . ,src)
696 (gethash snk (nth 4 current-plexus) nil))
697 (nth 4 current-plexus))
698 (when lbl
699 (progn
700 (puthash uid lbl (nth 5 current-plexus))
701 (puthash lbl uid (nth 6 current-plexus))))
702 ; Bump up nema counter if needed.
703 (when (> uid (cadr current-plexus))
704 (setcar (cdr current-plexus) uid)))))
705 \end{elisp}
707 \begin{notate}{On `add-en-masse'}
708 Given several articles, add all of them at once.
709 \end{notate}
711 \begin{elisp}
712 (defun add-en-masse (plex)
713 "Add multiple nemata given as list of quartuplets."
714 (mapcar (lambda (qplt)
715 (let ((uid (next-unique-id)))
716 (add-nema (nth 1 plex)
717 (nthcar 2 plex)
718 (nth 2 plex))
719 (label-nema uid (car qplt))))
720 plex))
721 \end{elisp}
723 \subsection{Query}
725 \begin{notate}{Overview of search and query functionality}
726 We first describe several elementary functions for
727 accessing elements of the network. We then describe a
728 robust search pipeline and show how it is implemented.
729 \end{notate}
731 \begin{notate}{Various lookup functions}
732 These functions allow testing and lookup of various elements
733 of a net.
734 \end{notate}
736 \begin{elisp}
737 (defun uid-p (uid)
738 "Is this a valid uid?"
739 (let ((z '(())))
740 (not (eq z (gethash uid (nth 2 current-plexus) z)))))
742 (defun uid-list ()
743 "List of all valid uid's."
744 (maphash (lambda (key val) key)
745 (nth 2 current-plexus)))
747 (defun ground-p (uid)
748 "Is this nema the ground?"
749 (= uid 0))
751 (defun source-p (x y)
752 "Is the former nema the sink of the latter?"
753 (equal x (get-source y)))
755 (defun sink-p (x y)
756 "Is the former nema the sink of the latter?"
757 (equal x (get-sink y)))
759 (defun links-from (x y)
760 "Return all links from nema x to nema y."
761 (filter '(lambda (z) (source-p x z))
762 (get-backward-links y)))
764 (defun links-p (x y)
765 "Does nema x link to nema y?"
766 (when (member x (mapcar
767 'get-source
768 (get-backward-links y)))
771 (defun triple-p (x y z)
772 "Do the three items form a triplet?"
773 (and (source-p y x)
774 (sink-p y z)))
776 (defun plexus-p (x)
777 "Is this object a plexus?"
778 (let ((ans t))
779 (setq ans (and ans
780 (equal (car x) "*plexus*")))
781 (setq ans (and ans
782 (integrp (cadr x))))
783 (dotimes (n 5)
784 (setq ans (and ans (hash-table-p
785 (nth (+ n 2) x)))))
786 ans))
787 \end{elisp}
789 \subsection{Iteration}
791 \begin{notate}{Iterating over a plexus}
792 These functions allow users to run loops over a plexus without
793 having to delve into its internal structure.\todo{I forget whether the
794 use of `apply' here is good form.}
795 \end{notate}
797 \begin{elisp}
798 (defmacro do-plexus (var res body)
799 `((maphash (lambda (,var val) ,body)
800 (nth 2 current-plexus))
801 ,res))
803 ;; This maps over the keys; func should be
804 ;; defined appropriately.
805 (defun map-plexus (func)
806 (let ((ans nil))
807 (maphash
808 (lambda (key val)
809 (push (apply func (list key)) ans))
810 (nth 2 current-plexus))
811 ans))
813 (defun filter-plexus (pred)
814 (let ((ans nil))
815 (maphash
816 (lambda (key val)
817 (when (apply pred (list key))
818 (push key ans)))
819 (nth 2 current-plexus))
820 ans))
821 \end{elisp}
823 \begin{notate}{Filtering convenience functions}
824 Several convenience functions for filtering the plexus can be
825 defined. They give lists of uids, which can be expanded
826 using get-triple.
827 \end{notate}
829 \begin{elisp}
830 (defun nemas-given-beginning (node)
831 "Get triples outbound from the given NODE."
832 (filter-plexus
833 (lambda (x) (when (equal (get-source x)
834 node)
835 (list node
836 (get-content x)
837 (get-sink x))))))
839 (defun nemas-given-end (node)
840 "Get triples inbound into NODE."
841 (filter-plexus
842 (lambda (x) (when (equal (get-sink x)
843 node)
844 (list (get-source x)
845 (get-content x)
846 node)))))
848 (defun nemas-given-middle (edge)
849 "Get the triples that run along EDGE."
850 (filter-plexus
851 (lambda (x) (when (equal (get-content x)
852 edge)
853 (list (get-source x)
854 edge
855 (get-sink x))))))
857 (defun nemas-given-middle-and-end (edge node)
858 "Get the triples that run along EDGE into NODE."
859 (filter-plexus
860 (lambda (x) (when (and
861 (equal (get-content x)
862 edge)
863 (equal (get-sink x)
864 node))
865 (list (get-source x)
866 edge
867 node)))))
869 (defun nemas-given-beginning-and-middle (node edge)
870 "Get the triples that run from NODE along EDGE."
871 (filter-plexus
872 (lambda (x) (when (and
873 (equal (get-source x)
874 node)
875 (equal (get-content x)
876 edge))
877 (list node
878 edge
879 (get-sink x))))))
881 (defun nemas-given-beginning-and-end (node1 node2)
882 "Get the triples that run from NODE1 to NODE2."
883 (filter-plexus
884 (lambda (x) (when (and
885 (equal (get-source x)
886 node1)
887 (equal (get-sink x)
888 node2))
889 (list node1
890 (get-content x)
891 node2)))))
893 (defun nemas-exact-match (node1 edge node2)
894 "Get the triples that run from NODE1 along EDGE to
895 NODE2."
896 (filter-plexus
897 (lambda (x) (when (and
898 (equal (get-source x)
899 node1)
900 (equal (get-content x)
901 edge)
902 (equal (get-sink x)
903 node2))
904 (list node1
905 edge
906 node2)))))
907 \end{elisp}
909 \begin{notate}{Additional elementary functions for node access}
910 These functions give access to the various parts of a node.\todo{Note:
911 since `article-list' is not defined, should these functions be deleted?
912 Or should they be rewritten to access `current-plexus'?}
913 \end{notate}
915 \begin{elisp}
916 (defun get-src (n)
917 (car (nth 0 (cdr (assoc n (cdr article-list))))))
919 (defun get-flk (n)
920 (cdr (nth 0 (cdr (assoc n (cdr article-list))))))
922 (defun get-txt (n)
923 (nth 1 (cdr (assoc n (cdr article-list)))))
925 (defun get-snk (n)
926 (car (nth 2 (cdr (assoc n (cdr article-list))))))
928 (defun get-blk (n)
929 (cdr (nth 2 (cdr (assoc n (cdr article-list))))))
931 (defun get-ids nil
932 (mapcar (quote car) (cdr article-list)))
934 (defun get-gnd nil 0)
935 \end{elisp}
937 \begin{notate}{On `search-cond'} \label{search-cond}
938 Surround the search within dolist loops on free variables.
939 Wrap no further when finished.\todo{Upgrade this to concatenate the results together.
940 Also maybe allow options to add headers or to
941 only loop over unique tuplets.}\todo{Explain; how does this differ from
942 the function defined at Note \ref{search}?}
943 \end{notate}
945 \begin{elisp}
946 (defmacro search-cond (vars prop)
947 "Find all n-tuplets satisfying a condition"
948 (let ((foo '(lambda (vars cmnd)
949 (if vars
950 Wrap in a loop.
951 `(dolist (,(car vars) uids)
952 ,(funcall foo (cdr vars) cmnd))
953 cmnd))))
954 (funcall foo vars prop)))
955 \end{elisp}
957 \begin{notate}{Overview of the search pipeline}
958 We will implement the search as a pipeline which gradually
959 transforms the query into a series of expressions which produce
960 the sought-after result, then evaluate those expressions.
962 A search query designates predicates apply to the nodes
963 and the network relationships that apply to them. The network relationships
964 function as wildcards.
966 The basic model of the data is triplets that point to other triplets.
967 The following query asks for a \emph{funny} link from a
968 \emph{big blue object} to a \emph{small green link} pointing outwards
969 from the big blue object.
970 \begin{idea}
971 (((a blue big) (b funny) (c green small)
972 ((b src a) (b snk c) (c src a))
973 \end{idea}
974 The first step of processing is to put the quaerenda in some
975 order so that each item links up with at least one previous item:
976 \begin{idea}
977 (scheduler
978 '((b funny)
979 (c green small))
980 '((b src a)
981 (b snk c)
982 (c src a))
983 '((a blue big)))
985 ((c (green small) ((b snk c) (c src a)))
986 (b (funny) ((b src a)))
987 (a blue big))
988 \end{idea}
989 Note that the order is reversed due to technicalities of
990 implementing `scheduler' --- that is to say, a is first and does
991 not link to any other variable, b is next and links to only a,
992 whilst c is last and links to both a and b.
993 At the same time, we have also rearranged things so that the
994 links to previous items to which a given object are listed
995 alongside that object. The next step is to replace the links with the commands which
996 generate a list of such objects:
997 \begin{idea}
998 ((c (green small) ((b snk c) (c src a)))
999 (b (funny) ((b src a)))
1000 (a blue big))
1002 ((c (green small)
1003 (intersection (list (get-snk b)) (get-forward-links a)))
1004 (b (funny)
1005 (intersection (get-backward-links a)))
1006 (a blue big))
1007 \end{idea}
1008 This is done using the function `tplts2cmd', e.g.
1009 \begin{idea}
1010 (tplts2cmd 'c '((b snk c) (c src a)))
1012 (intersection (list (get-snk b)) (get-forward-links a))
1013 \end{idea}
1014 Subsequently, we filter over the predicates:
1015 \begin{idea}
1016 ((c (filter '(lambda (c) (and (green c) (small c)))
1017 (intersection (list (get-snk b))
1018 (get-forward-links))))
1019 (b (filter '(lambda (b) (and (funny b)))
1020 (intersection (get-backward-links a)))))
1021 \end{idea}
1022 This is done with the command `add-filt':
1023 \begin{idea}
1024 (add-filt 'c
1025 '(green small)
1026 '((b snk c) (c src a)))
1028 (c (filter (quote (lambda (c) (and (green c) (small c))))
1029 (intersection (list (get-snk b))
1030 (get-forward-links a))))
1031 \end{idea}
1032 This routine calls up the previously described routine `tplts2cmd'
1033 to take care of the third argument. The last entry, {\tt (a blue big)}
1034 gets processed a little differently because we don't as yet have
1035 anything to filter over; instead, we generate the initial list by
1036 looping over the current network:
1037 \begin{idea}
1038 (a (let ((ans nil))
1039 (donet 'node
1040 (when (and (blue (get-content node))
1041 (big (get-content node)))
1042 (setq ans (cons node ans))))
1043 ans))
1044 \end{idea}
1045 This is done by invoking `first2cmd':
1046 \begin{idea}
1047 (first2cmd '(blue big))
1049 (let ((ans nil))
1050 (donet (quote node)
1051 (when (and (blue (get-content node))
1052 (big (get-content node)))
1053 (setq ans (cons node ans))))
1054 ans)
1055 \end{idea}
1056 And putting this all together:
1057 \begin{idea}
1058 (query2cmd
1059 '((c (green small) ((b snk c) (c src a)))
1060 (b (funny) ((b src a)))
1061 (a blue big)))
1063 ((c (filter (quote (lambda (c) (and (green c) (small c))))
1064 (intersection (list (get-snk b))
1065 (get-forward-links a))))
1066 (b (filter (quote (lambda (b) (and (funny b))))
1067 (intersection (get-forward-links a))))
1068 (a (let ((ans nil))
1069 (donet (quote node)
1070 (when (and (blue (get-content node))
1071 (big (get-content node)))
1072 (setq ans (cons node ans))))
1073 ans)))
1074 \end{idea}
1075 To carry out these instructions in the correct order and generate
1076 a set of variable assignments, we employ the `matcher' function.
1077 Combining this last layer, we have the complete pipeline:
1078 \begin{idea}
1079 (matcher nil
1080 (query2cmd
1081 (scheduler
1082 '((b funny)
1083 (c green small))
1084 '((b src a)
1085 (b snk c)
1086 (c src a))
1087 '((a blue big)))))
1088 \end{idea}
1089 This combination of operations is combined into the `search'
1090 function, which can be called as follows:
1091 \begin{idea}
1092 (search
1093 '(((a blue big)
1094 (b funny)
1095 (c green small))
1096 ((b src a)
1097 (b snk c)
1098 (c src a))))
1099 \end{idea}
1101 Having described what the functions are supposed to do and how
1102 they work together, we now proceed to implement them.
1103 \end{notate}
1105 \begin{notate}{On `scheduler'}
1106 The scheduler function takes a list search query and rearranges it
1107 into an order suitable for computing the answer to that query.
1108 Specifically, a search query is a pair of lists --- the first list
1109 consists of lists whose heads are names of variables and whose
1110 tails are predicates which the values of the variables should
1111 satisfy and the second list consists of triples indicating the
1112 relations between the values of the variables.
1113 Its arguments are:
1114 \begin{itemize}
1115 \item new-nodes, a list of items of the form \verbal|(node &rest property)|;
1116 \item \verbal|links|, a list of triplets;
1117 \item \verbal|sched| is a list whose items consist of triplets of the
1118 form\newline \verbal|(node (&rest property) (&rest link))|.
1119 \end{itemize}
1121 A recursive function to find linked nodes.
1122 If done, return answer.
1123 New nodes yet to be examined.
1124 Element of remaining-nodes currently under consideration.
1125 List of links between candidate and old-nodes.
1126 List of nodes already scheduled.
1127 Loop through new nodes until find one linked to an old node.
1128 Look at the next possible node.
1129 Find the old nodes linking to the candidate node and record the answer in ``ties''.
1130 Pick out the triplets whose first element is the node under consideration and whose third element is already on the list or vice-versa.
1131 Recursively add the rest of the nodes.
1132 \end{notate}
1134 \begin{elisp}
1135 (defun scheduler (new-nodes links sched)
1136 (if (null new-nodes)
1137 sched
1138 (let ((remaining-nodes new-nodes)
1139 (candidate nil)
1140 (ties nil)
1141 (old-nodes (mapcar 'car sched)))
1142 (while (null ties)
1143 (setq candidate (car remaining-nodes))
1144 (setq remaining-nodes (cdr remaining-nodes))
1145 (setq ties
1146 (filter '(lambda (x)
1148 (and (eq (first x) (car candidate))
1149 (member (third x) old-nodes))
1150 (and (member (first x) old-nodes)
1151 (eq (third x) (car candidate)))))
1152 links)))
1153 (scheduler (remove candidate new-nodes)
1154 links
1155 (cons (list (car candidate)
1156 (cdr candidate)
1157 ties)
1158 sched)))))
1159 \end{elisp}
1161 \begin{notate}{On `tplts2cmd'}
1162 \ldots\todo{Explain.}
1163 \end{notate}
1165 \begin{elisp}
1166 (defun tplts2cmd (var tplts)
1167 (cons 'intersection
1168 (mapcar
1169 #'(lambda (tplt)
1170 (cond ((and (eq (third tplt) var)
1171 (eq (second tplt) 'src))
1172 `(get-flk ,(first tplt)))
1173 ((and (eq (third tplt) var)
1174 (eq (second tplt) 'snk))
1175 `(get-blk ,(first tplt)))
1176 ((and (eq (first tplt) var)
1177 (eq (second tplt) 'src))
1178 `(list (get-src ,(third tplt))))
1179 ((and (eq (first tplt) var)
1180 (eq (second tplt) 'snk))
1181 `(list (get-snk ,(third tplt))))
1182 (t nil)))
1183 tplts)))
1184 \end{elisp}
1186 \begin{notate}{On `add-filt'}
1187 \ldots\todo{Explain.}
1188 \end{notate}
1190 \begin{elisp}
1191 (defun add-filt (var preds tplts)
1192 `(,var
1193 (filter
1194 #'(lambda (,var)
1195 ,(cons 'and
1196 (mapcar
1197 #'(lambda (pred)
1198 (list pred
1199 (list 'get-txt var)))
1200 preds)))
1201 ,(tplts2cmd var tplts))))
1202 \end{elisp}
1204 \begin{notate}{On `first2cmd'}
1205 \ldots\todo{Explain.}
1206 \end{notate}
1208 \begin{elisp}
1209 (defun first2cmd (preds)
1210 `(let ((ans nil))
1211 (dolist (node (get-ids) ans)
1212 (when
1213 ,(cons 'and
1214 (mapcar
1215 #'(lambda (pred)
1216 (cons pred '((get-txt node))))
1217 preds))
1218 (setq ans (cons node ans))))))
1219 \end{elisp}
1221 \begin{notate}{On `query2cmd'}
1222 \ldots\todo{Explain.}
1223 \end{notate}
1225 \begin{elisp}
1226 (defun query2cmd (query)
1227 (let ((backwards (reverse query)))
1228 (reverse
1229 (cons
1230 (list (caar backwards)
1231 (first2cmd (cdar backwards)))
1232 (mapcar
1233 #'(lambda (x)
1234 (add-filt (first x) (second x) (third x)))
1235 (cdr backwards))))))
1236 \end{elisp}
1238 \begin{notate}{On `matcher'}
1239 \ldots\todo{Explain.}
1240 \end{notate}
1242 \begin{elisp}
1243 (defun matcher (assgmt reqmts)
1244 (if (null reqmts) (list assgmt)
1245 (apply 'append
1246 (mapcar
1247 #'(lambda (x)
1248 (matcher (cons (list (caar reqmts) x)
1249 assgmt)
1250 (cdr reqmts)))
1251 (apply 'intersection
1252 (eval `(let ,assgmt
1253 (mapcar 'eval
1254 (cdar reqmts)))))))))
1255 \end{elisp}
1257 \begin{notate}{How matcher works}
1258 Here are some examples unrelated to what comes up in searching
1259 triplets which illustrate how matcher works:
1260 \end{notate}
1262 \begin{idea}
1263 (matcher '((x 1)) '((y (list 1 3))
1264 (z (list (+ x y) (- y x)))))
1266 (((z 2) (y 1) (x 1))
1267 ((z 0) (y 1) (x 1))
1268 ((z 4) (y 3) (x 1))
1269 ((z 2) (y 3) (x 1)))
1271 (matcher nil '((x (list 1))
1272 (y (list 1 3))
1273 (z (list (+ x y) (- y x)))))
1275 (((z 2) (y 1) (x 1))
1276 ((z 0) (y 1) (x 1))
1277 ((z 4) (y 3) (x 1))
1278 ((z 2) (y 3) (x 1)))
1279 \end{idea}
1281 \begin{notate}{On `search'} \label{search}
1282 \ldots\todo{Explain; how does this differ from
1283 the macro defined at Note \ref{search-cond}?}
1284 \end{notate}
1286 \begin{elisp}
1287 (defun search (query)
1288 (matcher nil
1289 (reverse
1290 (query2cmd
1291 (scheduler
1292 (cdar query)
1293 (cadr query)
1294 (list (caar query)))))))
1295 \end{elisp}
1297 \subsection{Scholium programming}
1299 \begin{notate}{Scholium programming}
1300 The next several functions allow us to store and retrieve code
1301 from inside of the network.
1302 \end{notate}
1304 \begin{notate}{On `node-fun'}
1305 \ldots\todo{Explain.}
1306 Produce a list of commands to produce temporary bindings.
1307 Produce a list of commands to reset function values.
1308 \end{notate}
1310 \begin{elisp}
1311 (defun node-fun (node get-code get-links)
1312 (let ((code (funcall get-code node))
1313 (links (funcall get-links node)))
1314 (list
1315 'lambda
1316 (car code)
1317 (cons
1318 'prog1
1319 (cons
1320 (append
1321 '(progn)
1322 (mapcar #'(lambda (x)
1323 `(fset ',(car x)
1324 (node-fun ,(cdr x)
1325 ',get-code
1326 ',get-links)))
1327 links)
1328 (cdr code))
1329 (mapcar #'(lambda (x)
1330 (if (fboundp (car x))
1331 `(fset ',(car x)
1332 ',(symbol-function (car x)))
1333 `(fmakunbound ',(car x))))
1334 links))))))
1335 \end{elisp}
1337 \begin{notate}{On `tangle-module'}
1338 Recursively replace the chunks to recover executable code.\todo{Explain.}
1339 \end{notate}
1341 \begin{elisp}
1342 (defun tangle-module (node get-cont ins-links)
1343 (insert-chunk
1344 (funcall get-cont node)
1345 (mapcar #'(lambda (x)
1346 (cons (car x)
1347 (tangle-module (cdr x)
1348 get-cont
1349 ins-links)))
1350 (funcall ins-links node))))
1351 \end{elisp}
1353 \begin{notate}{On `insert-chunk'}
1354 Given a node and an association list of replacement texts, insert
1355 the chunks at the appropriate places.
1356 \end{notate}
1358 \begin{elisp}
1359 (defun insert-chunk (body chunks)
1360 (cond ((null body) nil)
1361 ((null chunks) body)
1362 ((equal (car body) '*insert*)
1363 (cdr (assoc (cadr body) chunks)))
1364 (t (cons (insert-chunk (car body) chunks)
1365 (insert-chunk (cdr body) chunks)))))
1366 \end{elisp}
1368 \begin{notate}{Functions for rewriting nemas}
1369 Several functions for rewriting nemas.\todo{How does this stuff relate to what's
1370 going on in the vicinity of Note \ref{update-sink}?}
1371 \end{notate}
1373 \begin{elisp}
1374 (defun set-src (n x)
1375 (if (equal n 0)
1377 (progn (let ((old-backlink
1378 (nth 1 (assoc (get-src n)
1379 (cdr article-list)))))
1380 (setcdr old-backlink
1381 (delete n (cdr old-backlink))))
1382 (let ((new-backlink
1383 `(nth 1 (assoc x (cdr article-list)))))
1384 (setcdr new-backlink (cons n (cdr new-backlink))))
1385 (setcar (nth 1 (assoc n (cdr article-list))) x))))
1387 (defun set-txt (n x)
1388 (setcar (cdr (cdr (assoc n (cdr article-list)))) x))
1390 (defun set-snk (n x)
1391 (if (equal n 0)
1393 (progn (let ((old-backlink
1394 (nth 3 (assoc (get-snk n)
1395 (cdr article-list)))))
1396 (setcdr old-backlink
1397 (delete n (cdr old-backlink))))
1398 (let ((new-backlink
1399 (nth 3 (assoc x (cdr article-list)))))
1400 (setcdr new-backlink (cons n (cdr new-backlink))))
1401 (setcar (nth 3 (assoc n (cdr article-list))) x))))
1403 (defun ins-nod (src txt snk)
1404 (progn (setcdr article-list
1405 (cons (list (car article-list)
1406 (list src)
1408 (list snk))
1409 (cdr article-list)))
1410 (let ((backlink
1411 (nth 3 (assoc snk (cdr article-list)))))
1412 (setcdr backlink (cons (car article-list)
1413 (cdr backlink))))
1414 (let ((backlink
1415 (nth 1 (assoc src (cdr article-list)))))
1416 (setcdr backlink (cons (car article-list)
1417 (cdr backlink))))
1418 (- (setcar article-list (+ 1 (car article-list))) 1)))
1420 (defun del-nod (n)
1421 (if (or (equal n 0)
1422 (get-blk n)
1423 (get-flk n))
1425 (progn (let ((old-backlink
1426 (nth 3 (assoc (get-snk n)
1427 (cdr article-list)))))
1428 (setcdr old-backlink
1429 (delete n (cdr old-backlink))))
1430 (let ((old-backlink
1431 (nth 1 (assoc (get-src n)
1432 (cdr article-list)))))
1433 (setcdr old-backlink
1434 (delete n (cdr old-backlink))))
1435 (setcdr article-list
1436 (delete (assoc n (cdr article-list))
1437 (cdr article-list)))
1438 t)))
1439 \end{elisp}
1441 \subsection{Initialization}
1443 \begin{notate}{Initialize with a new network}
1444 For now, we just create one network to import things into. Additional
1445 networks can be added later (see Section \ref{applications}).
1446 \end{notate}
1448 \begin{elisp}
1449 (set-current-plexus (add-plexus))
1450 \end{elisp}
1452 \section{An example middle\"end} \label{middle-end}
1454 \begin{notate}{A middle\"end for managing collections of articles}
1455 This middle\"end is a set of functions that add triples into the
1456 backend. At this stage we basically ignore details of storage, and
1457 rely on the convenience functions defined above as the backend's API.
1458 In principle it would be possible to swap out the backend for another
1459 storage mechanism. We will give an example later on that uses more of
1460 the LISP-specific aspects of the backend implementation.\todo{Let's
1461 try to be a bit more concrete about this, especially in Section
1462 \ref{farm-demo}.} In this example, rather than talking about nemas
1463 and networks, we will talk about \emph{articles} and \emph{scholia}.
1464 These objects are things that user will want to access, create, and
1465 manipulate. However, we will deal with functions for user interaction
1466 (input, display, and editing) in Section \ref{frontend}, not here.
1467 Like the backend, the middle\"end could also be swapped out in
1468 applications where a different kind of data is modelled. And in fact,
1469 we come to some examples of other mid-level interfaces in Section
1470 \ref{applications}.
1471 \end{notate}
1473 \subsection{Database interaction} \label{interaction}
1475 \begin{notate}{The `article' function} \label{the-article-function}
1476 You can use this function to create an article with a
1477 given name and contents. You can optionally put it in a
1478 list by specifying the heading that it is under. (If this
1479 is used multiple times with the same heading, that just becomes
1480 a cone over the contents.)
1481 \end{notate}
1483 \begin{elisp}
1484 (defun article (name contents &optional heading)
1485 (let ((coordinates (add-nema name
1486 "has content"
1487 contents)))
1488 (when heading (add-nema coordinates "in" heading))
1489 coordinates))
1490 \end{elisp}
1492 \begin{notate}{The `scholium' function} \label{the-scholium-function}
1493 You can use this function to link annotations to objects.
1494 As with the `article' function, you can optionally
1495 categorize the connection under a given heading (cf. Note
1496 \ref{the-article-function}).
1497 \end{notate}
1499 \begin{elisp}
1500 (defun scholium (beginning link end &optional heading)
1501 (let ((coordinates (add-nema beginning
1502 link
1503 end)))
1504 (when heading (add-nema coordinates "in" heading))
1505 coordinates))
1506 \end{elisp}
1508 \begin{notate}{Uses of coordinates}
1509 It is convenient to do further immediate processing of the object
1510 we've created while we still have ahold of the coordinates
1511 returned by `add-nema' (e.g., for importing code
1512 that is adjacent to the article, see Note
1513 \ref{import-code-continuations}).
1514 \end{notate}
1516 \begin{notate}{On `get-article'} \label{get-article}
1517 Get the contents of the article named `name'.
1518 We assume that there is only one such article for now.
1519 \end{notate}
1521 \begin{elisp}
1522 (defun get-article (name)
1523 (get-sink
1524 (first
1525 (nemas-given-beginning-and-middle
1526 (first
1527 (nemas-given-beginning-and-end
1528 name "arxana-merge.tex"))
1529 "has content"))))
1530 \end{elisp}
1532 \begin{notate}{On `get-names'} \label{get-names}
1533 This function simply gets the names of articles that have
1534 names -- in other words, every triple built around the
1535 ``has content'' relation.\todo{This seems to work but
1536 are both map operations needed?}
1537 \end{notate}
1539 \begin{elisp}
1540 (defun get-names (&optional heading)
1541 (mapcar #'get-source
1542 (mapcar #'get-source (nemas-given-middle "has content"))))
1543 \end{elisp}
1545 \section{An example frontend} \label{frontend}
1547 \begin{notate}{Overview of the frontend}
1548 The frontend provides a demonstration of Arxana's functionality that
1549 is directly accessible to the user. Specifically, it is used to
1550 import \LaTeX\ documents into a network structure. They can then be
1551 edited, remixed, saved, browsed, and exported.\todo{Some of this
1552 functionality still needs to be merged in or written!}
1553 \end{notate}
1555 \subsection{Importing \LaTeX\ documents} \label{importing}
1557 \begin{notate}{Importing sketch} \label{importing-sketch}
1558 The code in this section imports a document, represented as a
1559 collection of (sub-)sections and notes. It gathers the sections,
1560 sub-sections, and notes recursively and records their content in a
1561 tree whose nodes are places and whose links express the
1562 ``component-of'' relation described in Note \ref{order-of-order}.
1564 This representation lets us see the geometric, hierarchical, structure
1565 of the document we've imported. It exemplifies a general principle,
1566 that geometric data should be represented by relationships between
1567 places, not direct relationships between strings. This is because
1568 ``the same'' string often appears in ``different'' places in any given
1569 document (e.g. a paper's many sub-sections titled ``Introduction''
1570 will not all have the same content).\todo{Do we need to relax this?}
1572 What goes into the places is in some sense arbitrary. The key is that
1573 whatever is in or attached to these places must tell us
1574 everything we need to know about the part of the document associated
1575 with that place (e.g., in the case of a note, its title and contents).
1576 That's over and above the structural links which say how the
1577 places relate to one another. Finally, all of these places and
1578 structural links will be added to a heading that represents the
1579 document as a whole.
1581 A natural convention we'll use is to put the name of any document
1582 component that's associated with a given place into that place, and
1583 add all other information as annotations.\todo{Does this contradict
1584 what is said above about Introductions?}
1586 Following our usual coding convention, functions are introduced
1587 below ``from the bottom up.''
1588 \end{notate}
1590 \begin{notate}{On `import-code-continuations'} \label{import-code-continuations}
1591 This function will run within the scope of `import-notes'.
1592 In fact, it is meant to run right after a Note itself
1593 has been scanned. The job of this function is to turn the
1594 series of Lisp chunks or other code snippets that follow a given note
1595 into a scholium attached to that note. Each separate snippet becomes
1596 its own annotation. The ``conditional regexps'' form used here only
1597 works with Emacs version 23 or higher.\todo{Note the use of an
1598 edge-pointing-to-an-edge for categorization; is this a good style?}
1599 \end{notate}
1601 \begin{elisp}
1602 ;; coords don't exist anymore, now we use uids
1603 (defun import-code-continuations (coords)
1604 (let ((possible-environments
1605 "\\(?1:elisp\\|idea\\|common\\)"))
1606 (while (looking-at
1607 (concat "\n*?\\\\begin{"
1608 possible-environments
1609 "}"))
1610 (let* ((beg (match-end 0))
1611 (environment (match-string 1))
1612 (end (progn (search-forward-regexp
1613 (concat "\\\\end{"
1614 environment
1615 "}"))
1616 (match-beginning 0)))
1617 (content (buffer-substring-no-properties
1619 end)))
1620 (scholium (scholium coords
1621 "has attachment"
1622 content)
1623 "has type"
1624 environment)))))
1625 \end{elisp}
1627 \begin{notate}{On `import-notes'} \label{import-notes}
1628 We're going to make the daring assumption that the ``textual''
1629 portions of incoming \LaTeX\ documents are contained in ``Notes''.
1630 That assumption is true, at least, for the current document. The
1631 function takes a buffer position `end' that denotes the end of the
1632 current section. The function returns the count of the number of
1633 notes imported, so that `import-within' knows where to start counting
1634 this section's non-note children.\todo{Would this same function work
1635 to import all notes from a buffer without examining its sectioning
1636 structure? Not quite, but close! (Could be a fun exercise to fix
1637 this.)}
1638 \end{notate}
1640 \begin{elisp}
1641 (defun import-notes (end)
1642 (let ((index 0))
1643 (while (re-search-forward (concat "\\\\begin{notate}"
1644 "{\\([^}\n]*\\)}"
1645 "\\( +\\\\label{\\)?"
1646 "\\([^}\n]*\\)?")
1647 end t)
1648 (let* ((name
1649 (match-string-no-properties 1))
1650 (tag (match-string-no-properties 3))
1651 (beg
1652 (progn (next-line 1)
1653 (line-beginning-position)))
1654 (end
1655 (progn (search-forward-regexp
1656 "\\\\end{notate}")
1657 (match-beginning 0)))
1658 ;; get the uid for our new nema
1659 (coords (add-nema name "in" buffername)))
1660 (scholium coords
1661 "has content"
1662 (buffer-substring-no-properties
1663 beg end))
1664 (setq index (1+ index))
1665 ;; current-parent is in scope inside import-within
1666 (scholium current-parent
1667 index
1668 coords
1669 buffername)
1670 (import-code-continuations coords)))
1671 index))
1672 \end{elisp}
1674 \begin{notate}{On `import-within'}
1675 Recurse through levels of sectioning in a document to import
1676 \LaTeX\ code. Children that are notes are attached to the
1677 hierarchical structure by the subroutine `import-notes', called by
1678 this function. Sections are attached directly by `import-within'. We
1679 observe that a note ``has content'' whereas a section does not.
1681 Incidentally, when looking for the end of an importing level, `nil' is
1682 an OK result: that describes the case when we have reached the
1683 \emph{last} section at this level \emph{and} there is no subsequent
1684 section at a higher level.
1685 \end{notate}
1687 \begin{elisp}
1688 (defun import-within (levels)
1689 (let ((this-level (car levels))
1690 (next-level (car (cdr levels))) answer)
1691 (while (re-search-forward
1692 (concat
1693 "^\\\\" this-level "{\\([^}\n]*\\)}"
1694 "\\( +\\\\label{\\)?"
1695 "\\([^}\n]*\\)?")
1696 level-end t)
1697 (let* ((name (match-string-no-properties 1))
1698 (at (add-nema name "in" buffername))
1699 (level-end
1700 (or (save-excursion
1701 (search-forward-regexp
1702 (concat "^\\\\" this-level "{.*")
1703 level-end t))
1704 level-end))
1705 (notes-end
1706 (if next-level
1707 (or (progn (point)
1708 (save-excursion
1709 (search-forward-regexp
1710 (concat "^\\\\"
1711 next-level "{.*")
1712 level-end t)))
1713 level-end)
1714 level-end))
1715 (index (let ((current-parent at))
1716 (import-notes notes-end)))
1717 (subsections (let ((current-parent at))
1718 (import-within (cdr levels)))))
1719 (while subsections
1720 (let ((coords (car subsections)))
1721 (setq index (1+ index))
1722 (scholium at
1723 index
1724 coords
1725 buffername)
1726 (setq subsections (cdr subsections))))
1727 (setq answer (cons at answer))))
1728 (reverse answer)))
1729 \end{elisp}
1731 \begin{notate}{On `import-buffer'}
1732 This function imports a \LaTeX\ document, taking care of
1733 the high-level, non-recursive, aspects of this operation.
1734 It imports frontmatter (everything up to the first
1735 \texttt{\textbackslash begin\{section\}}), but assumes ``backmatter'' is
1736 trivial, and does not attempt to import it. The imported
1737 material is classified as a ``document'' with the same
1738 name as the imported buffer.
1740 Links to sections will be made under the ``heading'' of this
1741 document.\todo{The sectioning levels should maybe be scholia attached
1742 to root-coords, but for some reason that wasn't working so well --
1743 investigate later -- maybe it just wasn't good to run after running
1744 `import-within'.}
1745 \end{notate}
1747 \begin{elisp}
1748 (defun import-buffer (&optional buffername)
1749 (save-excursion
1750 (set-buffer (get-buffer (or buffername
1751 (current-buffer))))
1752 (goto-char (point-min))
1753 (search-forward-regexp "\\\\begin{document}")
1754 (search-forward-regexp "\\\\section")
1755 (goto-char (match-beginning 0))
1756 (scholium buffername "is a" "document")
1757 (scholium buffername
1758 "has frontmatter"
1759 (buffer-substring-no-properties
1760 (point-min)
1761 (point))
1762 buffername)
1763 (let* ((root-coords (add-nema buffername "in" buffername))
1764 (levels
1765 '("section" "subsection" "subsubsection"))
1766 (current-parent buffername)
1767 (level-end nil)
1768 (sections (import-within levels))
1769 (index 0))
1770 (while sections
1771 (let ((coords (car sections)))
1772 (setq index (1+ index))
1773 (scholium root-coords
1774 index
1775 coords
1776 buffername))
1777 (setq sections (cdr sections))))))
1778 \end{elisp}
1780 \begin{notate}{On `autoimport-arxana'} \label{autoimport-arxana}
1781 This just calls `import-buffer', and imports this document
1782 into the system.
1783 \end{notate}
1785 \begin{elisp}
1786 (defun autoimport-arxana ()
1787 (interactive)
1788 (import-buffer "arxana-merge.tex"))
1789 \end{elisp}
1791 \subsection{Browsing database contents} \label{browsing}
1793 \begin{notate}{Browsing sketch} \label{browsing-sketch}
1794 This section facilitates browsing of documents represented
1795 with structures like those created in Section
1796 \ref{importing}, and sets the ground for browsing other
1797 sorts of contents (e.g. collections of tasks, as in
1798 Section \ref{managing-tasks}).
1800 In order to facilitate general browsing, it is not enough
1801 to simply use `get-article' (Note \ref{get-article}) and
1802 `get-names' (Note \ref{get-names}), although these
1803 functions provide our defaults. We must provide the means
1804 to find and display different things differently -- for
1805 example, a section's table of contents will typically
1806 be displayed differently from its actual contents.
1808 Indeed, the ability to display and select elements of
1809 document sections (Note \ref{display-section}) is
1810 basically the core browsing deliverable. In the process
1811 we develop a re-usable article selector (Note
1812 \ref{selector}; cf. Note \ref{browsing-tasks}). This in
1813 turn relies on a flexible function for displaying
1814 different kinds of articles (Note \ref{display-article}).
1815 \end{notate}
1817 \begin{notate}{On `display-article'} \label{display-article}
1818 This function takes in the name of the article to display.
1819 Furthermore, it takes optional arguments `retriever' and
1820 `formatter', which tell it how to look up and/or format
1821 the information for display, respectively.
1823 Thus, either we make some statement up front (choosing our
1824 `formatter' based on what we already know about the
1825 article), or we decide what to display after making some
1826 investigation of information attached to the article, some
1827 of which may be retrieved and displayed (this requires
1828 that we specify a suitable `retriever' and a complementary
1829 `formatter').
1831 For example, the major mode in which to display the
1832 article's contents could be stored as a scholium attached
1833 to the article; or we might maintain some information
1834 about ``areas'' of the database that would tell us up
1835 front what which mode is associated with the current area.
1836 (The default is to simply insert the data with no markup
1837 whatsoever.)
1839 Observe that this works when no heading argument is given,
1840 because in that case `get-article' looks for \emph{all}
1841 place pseudonyms. (But of course that won't work well
1842 when we have multiple theories containing things with the
1843 same names, so we should get used to using the heading
1844 argument.)
1846 (The business about requiring the data to be a sequence
1847 before engaging in further formatting is, of course, just
1848 a matter of expediency for making things work with the
1849 current dataset.)
1850 \end{notate}
1852 \begin{elisp}
1853 (defun display-article
1854 (name &optional heading retriever formatter)
1855 (interactive "Mname: ")
1856 (let* ((data (if retriever
1857 (funcall retriever name heading)
1858 (get-article name))))
1859 (when (and data (sequencep data))
1860 (save-excursion
1861 (if formatter
1862 (funcall formatter data heading)
1863 (pop-to-buffer (get-buffer-create
1864 "*Arxana Display*"))
1865 (delete-region (point-min) (point-max))
1866 (insert "NAME: " name "\n\n")
1867 (insert data)
1868 (goto-char (point-min)))))))
1869 \end{elisp}
1871 \begin{notate}{An interactive article selector} \label{selector}
1872 The function `get-names' (Note \ref{get-names}) and
1873 similar functions can give us a collection of articles.
1874 The next few functions provide an interactive
1875 functionality for moving through this collection to find
1876 the article we want to look at.
1878 We define a ``display style'' that the article selector
1879 uses to determine how to display various articles. These
1880 display styles are specified by text properties attached
1881 to each option the selector provides. Similarly, when
1882 we're working within a given heading, the relevant heading
1883 is also specified as a text property.
1885 At selection time, these text properties are checked to
1886 determine which information to pass along to
1887 `display-article'.
1888 \end{notate}
1890 \begin{elisp}
1891 (defvar display-style '((nil . (nil nil))))
1893 (defun thing-name-at-point ()
1894 (buffer-substring-no-properties
1895 (line-beginning-position)
1896 (line-end-position)))
1898 (defun get-display-type ()
1899 (get-text-property (line-beginning-position)
1900 'arxana-display-type))
1902 (defun get-relevant-heading ()
1903 (get-text-property (line-beginning-position)
1904 'arxana-relevant-heading))
1906 (defun arxana-list-select ()
1907 (interactive)
1908 (apply 'display-article
1909 (thing-name-at-point)
1910 (get-relevant-heading)
1911 (cdr (assoc (get-display-type)
1912 display-style))))
1914 (define-derived-mode arxana-list-mode fundamental-mode
1915 "arxana-list" "Arxana List Mode.
1917 \\{arxana-list-mode-map}")
1919 (define-key arxana-list-mode-map (kbd "RET")
1920 'arxana-list-select)
1921 \end{elisp}
1923 \begin{notate}{On `pick-a-name'} \label{pick-a-name}
1924 Here `generate' is the name of a function to call to
1925 generate a list of items to display, and `format' is a
1926 function to put these items (including any mark-up) into
1927 the buffer from which individiual items can then be
1928 selected.
1930 One simple way to get a list of names to display would be
1931 to reuse a list that we had already produced (this would
1932 save querying the database each time). We could, in fact,
1933 store a history list of lists of names that had been
1934 displayed previously (cf. Note \ref{local-storage}).
1936 We'll eventually want versions of `generate' that provide
1937 various useful views into the data, e.g., listing all of
1938 the elements of a given section (Note
1939 \ref{display-section}).
1941 Finding all the elements that match a given search term,
1942 whether that's just normal text search or some kind of
1943 structured search would be worthwhile too. Upgrading the
1944 display to e.g. color-code listed elements according to
1945 their type would be another nice feature to add.
1946 \end{notate}
1948 \begin{elisp}
1949 (defun pick-a-name (&optional generate format heading)
1950 (interactive)
1951 (let ((items (if generate
1952 (funcall generate)
1953 (reverse (get-names heading)))))
1954 (when items
1955 (set-buffer (get-buffer-create "*Arxana Articles*"))
1956 (toggle-read-only -1)
1957 (delete-region (point-min)
1958 (point-max))
1959 (if format
1960 (funcall format items)
1961 (mapc (lambda (item) (insert item "\n")) items))
1962 (toggle-read-only t)
1963 (arxana-list-mode)
1964 (goto-char (point-min))
1965 (pop-to-buffer (get-buffer "*Arxana Articles*")))))
1966 \end{elisp}
1968 \begin{notate}{On `get-section-contents'} \label{get-section-contents}
1969 This function is used by `display-section'
1970 (Note \ref{display-section}) to `pick-a-name' as a generator
1971 for the table of contents of the section with the given
1972 name under the given heading.
1974 This function first finds the triples that begin with the
1975 name of the section, then checks to see which of these represent structural
1976 information about that document. It also looks at the
1977 items found at via these links to see if they are
1978 sections or notes (``noteness'' is determined by them
1979 having content). The links are then sorted by their
1980 middles (which show the numerical order in which the components
1981 have in the section we're examining). After this ordering
1982 information has been used for sorting, it is deleted, and
1983 we're left with just a list of names in the appropriate
1984 order, together with an indication of their
1985 noteness.\todo{The initial import strategy used in
1986 the latest round (as of July 12 2017) doesn't
1987 seem to make the same assumptions about order of sections
1988 and their contents that are made in this function.}
1989 \end{notate}
1991 \begin{elisp}
1992 (defun get-section-contents (name heading)
1993 (let (contents)
1994 (dolist (triple (mapcar #'get-triple
1995 (nemas-given-beginning
1996 ;; ???
1997 name)))
1998 (when (get-triple
1999 ;; hopefully assuming uniqueness
2000 ;; doesn't defeat the purpose
2001 (first
2002 (nemas-exact-match
2003 (car triple) "in" heading)))
2004 (let* ((number (print-middle triple))
2005 (site (isolate-end triple))
2006 (noteness
2007 (when (get-triple
2008 (nemas-given-beginning-and-middle
2009 site "has content"))
2010 t)))
2011 (setq contents
2012 (cons (list number
2013 (print-system-object
2014 (place-contents site))
2015 noteness)
2016 contents)))))
2017 (mapcar 'cdr
2018 (sort contents
2019 (lambda (component1 component2)
2020 (< (parse-integer (car component1))
2021 (parse-integer (car component2))))))))
2022 \end{elisp}
2024 \begin{notate}{On `format-section-contents'} \label{format-section-contents}
2025 A formatter for document contents, used by
2026 `display-document' (Note \ref{display-document}) as input
2027 for `pick-a-name' (Note \ref{pick-a-name}).
2029 Instead of just printing the items one by one,
2030 like the default formatter in `pick-a-name' does,
2031 this version adds appropriate text properties, which
2032 we determine based the second component of
2033 of `items' to format.
2034 \end{notate}
2036 \begin{elisp}
2037 (defun format-section-contents (items heading)
2038 ;; just replicating the default and building on that.
2039 (mapc (lambda (item)
2040 (insert (car item))
2041 (let* ((beg (line-beginning-position))
2042 (end (1+ beg)))
2043 (unless (second item)
2044 (put-text-property beg end
2045 'arxana-display-type
2046 'section))
2047 (put-text-property beg end
2048 'arxana-relevant-heading
2049 heading))
2050 (insert "\n"))
2051 items))
2052 \end{elisp}
2054 \begin{notate}{On `display-section'} \label{display-section}
2055 When browsing a document, if you select a section, you
2056 should display a list of that section's constituent
2057 elements, be they notes or subsections. The question
2058 comes up: when you go to display something, how do you
2059 know whether you're looking at the name of a section, or
2060 the name of an article?
2062 When you get the section's contents out of the database
2063 (Note \ref{get-section-contents})
2064 \end{notate}
2066 \begin{elisp}
2067 (defun display-section (name heading)
2068 (interactive (list (read-string
2069 (concat
2070 "name (default "
2071 (buffer-name)
2072 "): ")
2073 nil nil (buffer-name))))
2074 ;; should this pop to the Articles window?
2075 (pick-a-name `(lambda ()
2076 (get-section-contents
2077 ,name ,heading))
2078 `(lambda (items)
2079 (format-section-contents
2080 items ,heading))))
2082 (add-to-list 'display-style
2083 '(section . (display-section
2084 nil)))
2085 \end{elisp}
2087 \begin{notate}{On `display-document'} \label{display-document}
2088 This file shows the top-level table of contents of a document.
2089 (Most typically, a list of all of that document's major sections.)
2090 In order to do this, we must find the triples that are begin at the node
2091 representing this document \emph{and} that are in the
2092 heading of this document. This boils down to treating the
2093 document's root as if it was a section and using the
2094 function `display-section' (Note \ref{display-section}).\todo{Assuming that
2095 the name comes from the current buffer is perhaps a bit odd.}
2096 \end{notate}
2098 \begin{elisp}
2099 (defun display-document (name)
2100 (interactive (list (read-string
2101 (concat
2102 "name (default "
2103 (buffer-name) "): ")
2104 nil nil (buffer-name))))
2105 (display-section name name))
2106 \end{elisp}
2108 \begin{notate}{Work with `heading' argument}
2109 We should make sure that if we know the heading we're
2110 working with (e.g. the name of the document we're
2111 browsing) that this information gets communicated in the
2112 background of the user interaction with the article
2113 selector.
2114 \end{notate}
2116 \begin{notate}{Selecting from a hierarchical display} \label{hierarchical-display}
2117 A fancier ``article selector'' would be able to display
2118 several sections with nice indenting to show their
2119 hierarchical order.
2120 \end{notate}
2122 \begin{notate}{Browser history tricks} \label{history-tricks}
2123 I want to put together (or put back together) something
2124 similar to the multihistoried browser that I had going in
2125 the previous version of Arxana and my Emacs/Lynx-based web
2126 browser, Nero\footnote{{\tt http://metameso.org/~joe/nero.el}}.
2127 The basic features are:
2128 (1) forward, back, and up inside the structure of a given
2129 document; (2) switch between tabs. More advanced features
2130 might include: (3) forward and back globally across all
2131 tabs; (4) explicit understanding of paths that loop.
2133 These sorts of features are independent of the exact
2134 details of what's printed to the screen each time
2135 something is displayed. So, for instance, you could flip
2136 between section manifests a la Note \ref{display-section},
2137 or between hierarchical displays a la Note
2138 \ref{hierarchical-display}, or some combination; the key
2139 thing is just to keep track in some sensible way of
2140 whatever's been displayed!
2141 \end{notate}
2143 \begin{notate}{Local storage for browsing purposes} \label{local-storage}
2144 Right now, in order to browse the contents of the
2145 database, you need to query the database every time. It
2146 might be handy to offer the option to cache names of
2147 things locally, and only sync with the database from time
2148 to time. Indeed, the same principle could apply in
2149 various places; however, it may also be somewhat
2150 complicated to set up. Using two systems for storage, one
2151 local and one permanent, is certainly more heavy-duty than
2152 just using one permanent storage system and the local
2153 temporary display. However, one thing in favor of local
2154 storage systems is that that's what I used in the the
2155 previous prototype of Arxana -- so some code already
2156 exists for local storage! (Caching the list of
2157 \emph{names} we just made a selection from would be one
2158 simple expedient, see Note \ref{pick-a-name}.)
2159 \end{notate}
2161 \begin{notate}{Hang onto absolute references}
2162 Since `get-article' (Note \ref{get-article}) translates
2163 strings into their ``place pseudonyms'', we may want to
2164 hang onto those pseudonyms, because they are, in fact, the
2165 absolute references to the objects we end up working with.
2166 In particular, they should probably go into the
2167 text-property background of the article selector, so it
2168 will know right away what to select!
2169 \end{notate}
2171 \subsection{Exporting \LaTeX\ documents$^*$}
2173 \begin{notate}{Roundtripping}
2174 The easiest test is: can we import a document into the
2175 system and then export it again, and find it unchanged?
2176 \end{notate}
2178 \begin{notate}{Data format}
2179 We should be able to \emph{stably} import and export a
2180 document, as well as export any modifications to the
2181 document that were generated within Arxana. This means
2182 that the exporting functions will have to read the data
2183 format that the importing functions use, \emph{and} that
2184 any functions that edit document contents (or structure)
2185 will also have to use the same format. Furthermore,
2186 \emph{browsing} functions will have to be somewhat aware
2187 of this format. So, this is a good time to ask -- did we
2188 use a good format?
2189 \end{notate}
2191 \subsection{Editing database contents$^*$} \label{editing}
2193 \begin{notate}{Roundtripping, with changes}
2194 Here, we should import a document into the system and then
2195 make some simple changes, and after exporting, check with
2196 diff to make sure the changes are correct.
2197 \end{notate}
2199 \begin{notate}{Re-importing}
2200 One nice feature would be a function to ``re-import'' a
2201 document that has changed outside of the system, and make
2202 changes in the system's version whereever changes appeared
2203 in the source version.
2204 \end{notate}
2206 \begin{notate}{Editing document structure}
2207 The way we have things set up currently, it is one thing
2208 to make a change to a document's textual components, and
2209 another to change its structure. Both types of changes
2210 must, of course, be supported.
2211 \end{notate}
2213 \section{Applications} \label{applications}
2215 \subsection{Managing tasks} \label{managing-tasks}
2217 \begin{notate}{What are tasks?}
2218 Each task tends to have a \emph{name}, a
2219 \emph{description}, a collection of \emph{prerequisite
2220 tasks}, a description of other \emph{material
2221 dependencies}, a \emph{status}, some \emph{justification
2222 of that status}, a \emph{creation date}, and an
2223 \emph{estimated time of completion}. There might actually
2224 be several ``estimated times of completion'', since the
2225 estimate would tend to improve over time. To really
2226 understand a task, one should keep track of revisions like
2227 this.
2228 \end{notate}
2230 \begin{notate}{On `store-task-data'} \label{store-task-data}
2231 Here, we're just filling in a frame. Since ``filling in a
2232 frame'' seems like the sort of operation that might happen
2233 over and over again in different contexts, to save space,
2234 it would probably be nice to have a macro (or similar)
2235 that would do a more general version of what this function
2236 does.
2237 \end{notate}
2239 \begin{elisp}
2240 (defun store-task-data
2241 (name description prereqs materials status
2242 justification submitted eta)
2243 (add-nema name "is a" "task")
2244 (add-nema name "description" description)
2245 (add-nema name "prereqs" prereqs)
2246 (add-nema name "materials" materials)
2247 (add-nema name "status" status)
2248 (add-nema name "status justification" justification)
2249 (add-nema name "date submitted" submitted)
2250 (add-nema name "estimated time of completion" eta))
2251 \end{elisp}
2253 \begin{notate}{On `generate-task-data'} \label{generate-task-data}
2254 This is a simple function to create a new task matching
2255 the description above.
2256 \end{notate}
2258 \begin{elisp}
2259 (defun generate-task-data ()
2260 (interactive)
2261 (let ((name (read-string "Name: "))
2262 (description (read-string "Description: "))
2263 (prereqs (read-string
2264 "Task(s) this task depends on: "))
2265 (materials (read-string "Material dependencies: "))
2266 (status (completing-read
2267 "Status (tabled, in progress, completed):
2268 " '("tabled" "in progress" "completed")))
2269 (justification (read-string "Why this status? "))
2270 (submitted
2271 (read-string
2272 (concat "Date submitted (default "
2273 (substring (current-time-string) 0 10)
2274 "): ")
2275 nil nil (substring (current-time-string) 0 10)))
2276 (eta
2277 (read-string "Estimated date of completion:")))
2278 (store-task-data name description prereqs materials
2279 status
2280 justification submitted eta)))
2281 \end{elisp}
2283 \begin{notate}{Possible enhancements to `generate-task-data'}
2284 In order to make this function very nice, it would be good
2285 to allow ``completing read'' over known tasks when filling
2286 in the prerequisites. Indeed, it might be especially nice
2287 to offer a type of completing read that is similar in some
2288 sense to the tab-completion you get when completing a file
2289 name, i.e., quickly completing certain sub-strings of the
2290 final string (in this case, these substrings would
2291 correspond to task areas we are progressively zooming down
2292 into).
2294 As for the task description, rather than forcing the user
2295 to type the description into the minibuffer, it might be
2296 nice to pop up a separate buffer instead (a la the
2297 Emacs/w3m textarea). If we had a list of all the known
2298 tasks, we could offer completing-read over the names of
2299 existing tasks to generate the list of `prereqs'. It
2300 might be nice to systematize date data, so we could more
2301 easily e.g. sort and display task info ``by date''.
2302 (Perhaps we should be working with predefined database
2303 types for dates and so on.)
2305 Also, before storing the task, it might be nice to offer
2306 the user the chance to review the data they entered.
2307 \end{notate}
2309 \begin{notate}{On `get-filler'} \label{get-filler}
2310 Just a wrapper for `nemas-given-beginning-and-middle'.
2311 (Maybe we should add `heading' as an optional argument here.)
2312 \end{notate}
2314 \begin{elisp}
2315 (defun get-filler (frame slot)
2316 (third (first
2317 (print-triples
2318 (mapcar #'get-triple
2319 (nemas-given-beginning-and-middle frame
2320 slot))))))
2321 \end{elisp}
2323 \begin{notate}{On `get-task'} \label{get-task}
2324 Uses `get-filler' (Note \ref{get-filler}) to assemble the
2325 elements of a task's frame.
2326 \end{notate}
2328 \begin{elisp}
2329 (defun get-task (name)
2330 (when (triple-exact-match name "is a" "task")
2331 (list (get-filler name "description")
2332 (get-filler name "prereqs")
2333 (get-filler name "materials")
2334 (get-filler name "status")
2335 (get-filler name "status justification")
2336 (get-filler name "date submitted")
2337 (get-filler name
2338 "estimated time of completion"))))
2339 \end{elisp}
2341 \begin{notate}{On `review-task'} \label{review-task}
2342 This is a function to review a task by name.
2343 \end{notate}
2345 \begin{elisp}
2346 (defun review-task (name)
2347 (interactive "MName: ")
2348 (let ((task-data (get-task name)))
2349 (if task-data
2350 (display-task task-data)
2351 (message "No data."))))
2353 (defun display-task (data)
2354 (save-excursion
2355 (pop-to-buffer (get-buffer-create
2356 "*Arxana Display*"))
2357 (delete-region (point-min) (point-max))
2358 (insert "NAME: " name "\n\n")
2359 (insert "DESCRIPTION: " (first data) "\n\n")
2360 (insert "TASKS THIS TASK DEPENDS ON: "
2361 (second data) "\n\n")
2362 (insert "MATERIAL DEPENDENCIES: "
2363 (third data) "\n\n")
2364 (insert "STATUS: " (fourth data) "\n\n")
2365 (insert "WHY THIS STATUS?: " (fifth data) "\n\n")
2366 (insert "DATE SUBMITTED:" (sixth data) "\n\n")
2367 (insert "ESTIMATED TIME OF COMPLETION: "
2368 (seventh data) "\n\n")
2369 (goto-char (point-min))
2370 (fill-individual-paragraphs (point-min) (point-max))))
2371 \end{elisp}
2373 \begin{notate}{Possible enhancements to `review-task'}
2374 Breaking this down into a function to select the task and
2375 another function to display the task would be nice. Maybe
2376 we should have a generic function for selecting any object
2377 ``by name'', and then special-purpose functions for
2378 displaying objects with different properties.
2380 Using text properties, we could set up a ``field-editing
2381 mode'' that would enable you to select a particular field
2382 and edit it independently of the others. Another more
2383 complex editing mode would \emph{know} which fields the
2384 user had edited, and would store all edits back to the
2385 database properly. See Section \ref{editing} for more on
2386 editing.
2387 \end{notate}
2389 \begin{notate}{Browsing tasks} \label{browsing-tasks}
2390 The function `pick-a-name' (Note \ref{pick-a-name}) takes
2391 two functions, one that finds the names to choose from,
2392 and the other that says how to present these names. We
2393 can therefore build `pick-a-task' on top of `pick-a-name'.
2394 \end{notate}
2396 \begin{elisp}
2397 (defun get-tasks ()
2398 (mapcar #'first
2399 (print-triples
2400 (mapcar #'get-triple
2401 (nemas-given-middle-and-end "is a" "task")
2402 t))))
2404 (defun pick-a-task ()
2405 (interactive)
2406 (pick-a-name
2407 'get-tasks
2408 (lambda (items)
2409 (mapc (lambda (item)
2410 (let ((pos (line-beginning-position)))
2411 (insert item)
2412 (put-text-property pos (1+ pos)
2413 'arxana-display-type
2414 'task)
2415 (insert "\n"))) items))))
2417 (add-to-list 'display-style
2418 '(task . (get-task display-task)))
2419 \end{elisp}
2421 \begin{notate}{Working with theories}
2422 Presumably, like other related functions, `get-tasks'
2423 should take a heading argument.
2424 \end{notate}
2426 \begin{notate}{Check display style}
2427 Check if this works, and make style consistent between
2428 this usage and earlier usage.
2429 \end{notate}
2431 \begin{notate}{Example tasks}
2432 It might be fun to add some tasks associated with
2433 improving Arxana, just to show that it can be done...
2434 maybe along with a small importer to show how importing
2435 something without a whole lot of structure can be easy.
2436 \end{notate}
2438 \begin{notate}{Org mode integration}
2439 The ``default'' task manager on Emacs is Org mode. It would be good
2440 to provide integration between Org mode and Arxana. This is one of
2441 the first things that Emacs people ask about when they hear about
2442 Arxana.
2443 \end{notate}
2445 \subsection{``Modelling mathematics the way it is really done''} \label{farm-demo}
2447 \begin{notate}{Demonstration of an application to modelling mathematics}
2448 In a paper for the 5th ACM SIGPLAN International Workshop on
2449 Functional Art, Music, Modelling and Design (FARM 2017), we talk about
2450 how Arxana can be applied to model mathematical proofs. A rather
2451 advanced form of ``mathematical knowledge management'' is proposed,
2452 that integrates dialogue, heuristics, and that ultimately moves in the
2453 direction of an AI system. In this section, we will walk through this
2454 application.
2456 The basic idea here is to write an interpreter that will read
2457 s-expressions and convert them into triples in the backend. So we
2458 will need a function that reads s-exps into some designated storage.
2459 The s-expressions are constrained to follow the grammar defined
2460 for the Inference Anchoring Theory + Content (IATC) language.
2461 The primatives of this language are described below. The
2462 number of arguments is indicated in the variable name.
2463 (1.5 means that it takes one and, optionally, two arguments.)
2465 We will create a new plexus to store this content.
2466 \end{notate}
2468 \begin{elisp}
2469 (add-plexus)
2471 ;; (with-current-plexus (second plexus-registry)
2472 ;; (add-nema "this" "is a" "test"))
2474 (defvar iatc-performatives-2 '(Define))
2475 (defvar iatc-performatives-1.5 '(Assert Agree Challenge Retract))
2476 (defvar iatc-performatives-1 '(Suggest Judge Query))
2477 (defvar iatc-performatives-A '(QueryE))
2479 (defvar iatc-intermediate-2 '(implies strategy auxiliary analogy
2480 implements generalises wlog
2481 has_property instance_of
2482 indep_of))
2483 (defvar iatc-intermediate-1.5 '(easy))
2484 (defvar iatc-intermediate-1 '(not goal plausible beautiful useful
2485 heuristic))
2486 (defvar iatc-intermediate-A '(conjunction and))
2487 (defvar iatc-intermediate-1A '(case_split))
2489 (defvar iatc-content-2 '(used_in sub_prop reform instantiates
2490 expands sums))
2491 (defvar iatc-content-1 '(extensional_set))
2493 (defvar iatc-verbs (append iatc-performatives-2 iatc-performatives-1.5 iatc-performatives-1
2494 iatc-performatives-A iatc-intermediate-2 iatc-intermediate-1.5
2495 iatc-intermediate-1 iatc-intermediate-A iatc-intermediate-1A
2496 iatc-content-2 iatc-content-1))
2497 \end{elisp}
2499 \begin{notate}{Second attempt}
2500 This code is based on the simpler idea of printing parent-child
2501 relationships.\footnote{\url{https://stackoverflow.com/a/45772888/821010}}
2502 But it is a bit more complicated, partly because we need different behaviour
2503 in the different cases outlined above.
2505 It would be nice, and, actually, necessary, to have ``multiple''
2506 return values, per the example below. The reason we need these return
2507 values is that new structure is developed relative to existing graph
2508 structure.
2510 The function works recursively. It will always turn the top-level
2511 verb into a nema and return it. It will also create one or more nemas
2512 along the way (behaviour depends on the specific verb).
2514 We also want to build up a structure that mirrors the tree that was
2515 put in, but that shows how the elements of that structure have been
2516 mapped into the graph.
2517 \end{notate}
2519 \begin{elisp}
2520 (defun sexps-to-subgraph (tree &rest more)
2521 ;; This function will take in a tree (or maybe several) that
2522 ;; indicate a given subgraph, mark this subgraph with a cone,
2523 ;; and return a handle to the cone.
2524 (let ((indicated-nodes (lambda () #'car tree)))
2525 ;; note that the cone itself can be stored as a list
2526 ;; of nemas
2529 (defun get-verbs (tree)
2530 (let ((head (car tree))
2531 (tail (cdr tree)))
2532 (append
2533 (if (consp head)
2534 (get-verbs head)
2535 (list head))
2536 (let (acc)
2537 (while tail
2538 (setq child (car tail)
2539 tail (cdr tail))
2540 ;; we are only interested in recursing to add'l
2541 ;; function applications
2542 (when (consp child)
2543 (setq acc (append (get-verbs child) acc))))
2544 acc))))
2546 ; (get-verbs '(a (b (c 1 2)) 8 9 (d (e 1 2 3) (g 4 5))))
2548 (defun highlight-tree-wrapper (tree)
2549 (second (highlight-tree tree)))
2551 (defun highlight-tree (tree &optional highlights)
2552 (with-current-plexus
2553 (second plexus-registry)
2554 ;; Cases:
2555 ;; IATC - create an internal identifier for it.
2556 ;; generic hcode - store the whole form as the contents of a node.
2557 ;; already-imported IATC - don't import it again, just refer to it
2558 (if (member (car tree) iatc-verbs)
2559 ;; yes the verb is an iatc-verb: we need to import the tree ->
2560 (let* ((verb (car tree))
2561 (symb (gensym (symbol-name verb)))
2562 (atom (add-nema 0 symb 0))
2563 (label (label-nema atom symb))
2564 (type (add-nema symb "type" verb)))
2565 ;; maybe this should be (rplaca tree symb), though that's destructive
2566 ;; (cons symb highlights)
2567 (cond ((string= (symbol-name verb) "and")
2568 ;; (same as the default clause; including this clause just
2569 ;; for illustrative purposes for now.)
2570 (dolist (child (cdr tree))
2571 (add-nema atom
2573 (if (consp child)
2574 (first (highlight-tree child))
2575 child))))
2576 ;; Here, an *implies* node is broken down into two edges:
2577 ;; one pointing to its antecedent and one pointing to its
2578 ;; consequent
2579 ((string= (symbol-name verb) "implies")
2580 (let ((antecedent (first (cdr tree)))
2581 (consequent (second (cdr tree))))
2582 (add-nema atom
2583 "antecedent"
2584 (if (consp antecedent)
2585 (first (highlight-tree antecedent))
2586 antecedent))
2587 (add-nema atom
2588 "consequent"
2589 (if (consp consequent)
2590 (first (highlight-tree consequent))
2591 consequent))))
2593 ;; default behaviour covers these verbs:
2594 ;; and (multiple clauses), analogy (do we need to check that it only has 2 terms?)
2595 (dolist (child (cdr tree))
2596 (add-nema atom
2598 (if (consp child)
2599 (first (highlight-tree child))
2600 child)))))
2601 (rplaca tree symb)
2602 (list atom tree))
2603 ;; no the verb is not an iatc verb:
2604 ;; we therefore assume it has been imported already
2605 ;; ...which might not be the case if we were dealing with full
2606 ;; ...hcode markup, but let's deal with that separately, later
2607 ;; and we will treat the whole s-exp as representative
2608 ;; of a subgraph, which needs to be retrieved and suitably *marked up*,
2609 ;; and some handle for this subgraph should be returned
2611 \end{elisp}
2613 \begin{notate}{A simple analogy}
2614 The first example is, on the face of it, a very simple analogy. The
2615 answer to the mathematical question that it poses is turns out to be more
2616 complicated! Note that while it builds up a structure in the backend,
2617 the interpreter returns some convenient handles for the contents that
2618 are entered.
2619 \end{notate}
2621 \begin{idea}
2622 (Assert (implies (and "G finite group"
2623 "H subgroup of G"
2624 "[G : H] finite")
2625 "G not equal to union of ghg^-1"))
2626 ;=> %1-implies, %1-and
2628 (Assert (analogy
2629 %1-implies
2630 (implies (and "G infinite group"
2631 "H subgroup of G"
2632 "[G : H] finite")
2633 "G not equal to union of ghg^-1")))
2634 ;=> %2-analogy, %2-implies
2636 (Question %2-implies)
2637 ;=> nil
2638 \end{idea}
2640 \begin{notate}{A challenge problem}
2641 The second example is a full solution to a challenge problem.
2642 \end{notate}
2644 \begin{idea}
2645 ;; What is the 500th digit of (sqrt(3)+sqrt(2))^2012?
2647 (Assert
2648 "goal"
2649 "compute 500th digit of (sqrt(3)+sqrt(2))^2012")
2651 ;; Even this...
2653 (Assert (exists (strategy "goal"
2654 "strategy X")))
2656 (Assert (has_property "strategy X"
2657 "HAL"))
2659 ;; For now...
2661 (Suggest (strategy goal
2662 "simplify and compute"))
2664 ;; Furthermore...
2666 (Suggest (strategy goal
2667 "this should be straightforward
2668 once we find the trick"))
2670 ;; Can we do...
2672 (Assert
2673 (analogy
2674 "compute 500th digit of (sqrt(2)+sqrt(3))^2012"
2675 "compute 500th digit of (x+y)^2012"))
2677 (Assert
2678 (analogy
2679 "compute 500th digit of (sqrt(2)+sqrt(3))^2012"
2680 "compute 500th digit of e^2012"))
2682 (Assert
2683 (analogy
2684 "compute 500th digit of (sqrt(2)+sqrt(3))^2012"
2685 "compute 500th digit of r^2012,
2686 where r is a rational with small denominator"))
2688 (Assert
2689 (has_property
2690 "compute 500th digit of r^2012,
2691 where r is a rational with small denominator"
2692 "we can really compute this"))
2694 (Assert
2695 (has_evidence
2696 "we can really compute this"
2697 "e.g. 500th digit of (1/10)^2012 is 0"))
2699 ;; How about small...
2701 (Suggest (strategy goal
2702 "the trick might be: it
2703 is close to something
2704 we can compute"))
2706 ;; mth digit of...
2708 (Suggest (auxilliary
2709 "generalise"
2710 "general form of the problem:
2711 mth digit of (sqrt(3)+sqrt(2))^n"))
2713 ;; (sqrt(3)+sqrt(2))^2
2715 (Suggest (auxilliary
2716 "specialise"
2717 "(sqrt(3)+sqrt(2))^2"))
2719 (Assert (instantiates
2720 "(sqrt(3)+sqrt(2))^2"
2721 "general form of the problem:
2722 mth digit of (sqrt(3)+sqrt(2))^n"))
2724 (Assert (has_property
2725 "(sqrt(3)+sqrt(2))^2"
2726 "we can really compute this"))
2728 ;; 2 + 2 sqrt(2) sqrt(3) + 3
2730 (Assert (expands
2731 "(sqrt(3)+sqrt(2))^2"
2732 "2 + 2 sqrt(3) sqrt(2) + 3"))
2734 ;; (sqrt(3)+sqrt(2))^2 + (sqrt(3)-sqrt(2))^2 = 10
2736 (Suggest (strategy "eliminate cross terms"))
2738 (Assert (expands "(sqrt(3)+sqrt(2))^2 + (sqrt(3)-sqrt(2))^2"
2739 "2 + 2 sqrt(2) sqrt(3) + 3
2740 + 2 - 2 sqrt(2) sqrt(3) + 3"))
2742 (Assert (sums "2 + 2 sqrt(2) sqrt(3) + 3
2743 + 2 - 2 sqrt(2) sqrt(3) + 3"
2744 "10"))
2746 ;; (sqrt(3)+sqrt(2))^2012 + (sqrt(3)-sqrt(2))^2012 is an integer
2748 (Suggest (strategy "binomial theorem"))
2750 (Assert (generalises "binomial theorem"
2751 "eliminate cross terms"))
2753 (Assert (sums "(sqrt(3)+sqrt(2))^2012 + (sqrt(3)-sqrt(2))^2012"
2754 "some integer"))
2756 ;; And (sqrt(3)-sqrt(2))^2012 is a very small number
2758 (Assert (contains_as_summand
2759 "(sqrt(2)+sqrt(3))^2012+(sqrt(3)-sqrt(2))^2012"
2760 "(sqrt(3)-sqrt(2))^2012"))
2762 (Assert (has_property "(sqrt(3)-sqrt(2))^2012"
2763 "is small"))
2765 (Assert (implements #SUBGRAPH
2766 "the trick might be: it
2767 is close to something
2768 we can compute"))
2770 (Suggest (strategy "numbers that are very close
2771 to integers have \"9\"
2772 in many places of their
2773 decimal expansion"))
2775 ;; We need to check...
2777 (Assert "sqrt(3)-sqrt(2)<1/2")
2778 (Assert "0<a<b<1 => a^N < b^N")
2779 (Assert "(1/2)^2012 = ((1/2)^4)^503")
2780 (Assert "(1/2)^4 = 1/16")
2781 (Assert "1/16 < .1")
2782 (Assert ".1^503 has 502 0's
2783 in its decimal expansion")
2784 (Assert "an integer minus something with
2785 at least 502 0's in its decimal
2786 expansion has at least 503 9's
2787 in its decimal expansion")
2789 (Assert (implies #SUBGRAPH2
2790 "(sqrt(2)+sqrt(3))^2012
2791 = (sqrt(2)+sqrt(3))^2012
2792 +(sqrt(2)+sqrt(3))^2012
2793 -(sqrt(2)-sqrt(3))^2012
2794 has at least 503 9's in its
2795 decimal expansion"))
2797 (Assert (has_specialisation
2798 "(sqrt(2)+sqrt(3))^2012
2799 = (sqrt(2)+sqrt(3))^2012
2800 +(sqrt(2)+sqrt(3))^2012
2801 -(sqrt(2)-sqrt(3))^2012
2802 has at least 503 9's in its
2803 decimal expansion"
2804 "(sqrt(2)+sqrt(3))^2012 has 500
2805 9s in its decimal expansion"))
2807 (Assert "(sqrt(2)+sqrt(3))^2012 has 500
2808 9s in its decimal expansion")
2809 \end{idea}
2811 \section{Conclusion} \label{conclusion}
2813 \begin{notate}{Ending and beginning again}
2814 This is the end of this Arxana demo system. Contributions that
2815 support the development of the Arxana project are welcome.
2816 \end{notate}
2818 \appendix
2820 \section{Appendix: A simple literate programming system} \label{appendix-lit}
2822 \begin{notate}{The literate programming system used in this paper}
2823 This code defines functions that grab all the Lisp portions of this
2824 document, and evaluates the Emacs Lisp sections. It requires that the
2825 \LaTeX\ be written in a certain consistent way. The function assumes
2826 that this document is the current buffer.
2828 \begin{verbatim}
2829 (defvar lit-code-beginning-regexp
2830 "^\\\\begin{elisp}")
2832 (defvar lit-code-end-regexp
2833 "^\\\\end{elisp}")
2835 (defvar lit-count 0)
2837 (defun lit-eval ()
2838 (interactive)
2839 (lit-process 'eval))
2841 (defun lit-process (&optional code)
2842 (interactive)
2843 (setq lit-count (1+ lit-count))
2844 (save-excursion
2845 (let ((to-buffer (concat "*Lit Code " (int-to-string
2846 lit-count)"*"))
2847 (from-buffer (buffer-name (current-buffer))))
2848 (set-buffer (get-buffer-create to-buffer))
2849 (erase-buffer)
2850 (set-buffer (get-buffer-create from-buffer))
2851 (goto-char (point-min))
2852 (while (re-search-forward
2853 lit-code-beginning-regexp nil t)
2854 (let* ((beg (match-end 0))
2855 (end (save-excursion
2856 (search-forward-regexp
2857 lit-code-end-regexp nil t)
2858 (match-beginning 0)))
2859 (match (buffer-substring beg end)))
2860 (save-excursion
2861 (set-buffer to-buffer)
2862 (insert match))))
2863 (case code
2864 ('eval
2865 (set-buffer to-buffer)
2866 (eval-buffer)
2867 ;; (kill-buffer (current-buffer))
2870 (switch-to-buffer to-buffer))))))
2871 \end{verbatim}
2872 \end{notate}
2874 \begin{notate}{A literate style}
2875 Ideally, each function will have its own Note to introduce
2876 it, and will not be called before it has been defined. I
2877 sometimes make an exception to this rule, for example,
2878 functions used to form recursions may appear with no
2879 further introduction, and may be called before they are
2880 defined.
2881 \end{notate}
2883 \clearpage
2884 \printindex
2886 \end{document}