diff --git a/example/dots/exampleBQNp7Z.svg b/example/dots/exampleBQNp7Z.svg new file mode 100644 index 0000000..8ec5356 --- /dev/null +++ b/example/dots/exampleBQNp7Z.svg @@ -0,0 +1,53 @@ + + + + + + +G + + + +node0 + +c + + + +node1 + +b + + + +node0->node1 + + + + +node2 + +a + + + +node2->node0 + + + + + +node2->node1 + + + + + +node2->node2 + + + + diff --git a/example/example.org b/example/example.org new file mode 100644 index 0000000..d4a42ec --- /dev/null +++ b/example/example.org @@ -0,0 +1,319 @@ +#+TITLE: Examples of usage of =dds= + +#+PROPERTY: header-args:racket :prologue "#lang racket\n(require graph (file \"~/Candies/prj/racket/dds/networks.rkt\") (file \"~/Candies/prj/racket/dds/utils.rkt\"))" + +* Introduction + This document shows some examples of usage of the modules in =dds= + with Org-mode. It relies on [[https://github.com/hasu/emacs-ob-racket][emacs-ob-racket]]. + + The [[intro][following section]] describes how Org-mode can interact with + Racket, and how this interaction can be used for a fluid workflow + with =dds=. In particular, the code block =munch-table= is [[tabread][defined]] + in this section. + + The subsequent sections show off some the functionalities of the + submodules of =dds=. + +* Org-mode, Racket, and =dds= <> +** Importing a module from file + :PROPERTIES: + :header-args:racket: :prologue "#lang racket\n(require (file \"~/Candies/prj/racket/dds/networks.rkt\"))" + :END: + + To require the modules from the files of =dds=, you can use the + following code (I only reset the prelude here because I set at the + top of this file): + + #+BEGIN_SRC racket :results output :prologue "" +#lang racket +(require (file "~/Candies/prj/racket/dds/networks.rkt")) +(require (file "~/Candies/prj/racket/dds/utils.rkt")) + #+END_SRC + + #+RESULTS: + + Note that this code will not work with =:results value=. I think it + is because in this case the code is not really evaluated at top + level. + + These initialisation lines can be put into the prologue of every + code block in a subtree by setting =:prologue= via + =:header-args:racket:= in the properties drawer. Check out the + properties drawer of this section for an example. + + Alternatively, this property can be set via a =#+PROPERTY= line at + the top the file. For example, this file has such a line. Whenever + this property line changes, refresh the setup of the file by hitting + =C-c C-c= on the property line. This will update the prologue for + all racket code blocks. + + Finally, you can also set =:prologue= (and other properties with + long values) in the following way: + + #+HEADER: :prologue "#lang racket\n(require (file \"~/Candies/prj/racket/dds/networks.rkt\"))" + #+BEGIN_SRC racket :results output drawer +(st '((a . 1))) + #+END_SRC + + #+RESULTS: + :RESULTS: + '#hash((a . 1)) + :END: + +** Output formats for results of evaluation of code blocks + [[https://orgmode.org/manual/Results-of-Evaluation.html#Results-of-Evaluation][This section]] of the Org manual describes various different formats + for presenting the results of code blocks. I find the following + three particularly useful as of [2020-02-22 Sat]: =output=, =list=, + and =table=. + + The =output= result format is the simplest and the most natural + ones. It works as if the code block were inserted into a module + which would then be evaluated. + + #+BEGIN_SRC racket :results output drawer +(println "This is the first line of output.") +(println (+ 1 2)) +(println "This the third line of output.") + #+END_SRC + + #+RESULTS: + :RESULTS: + "This is the first line of output." + 3 + "This the third line of output." + :END: + + The =list= result format typesets the result of the last line in the + code block as a list: + #+BEGIN_SRC racket :results list +'(1 "hello" (and x y)) + #+END_SRC + + #+RESULTS: + - 1 + - "hello" + - (and x y) + + Note how nested lists are not recursively shown as nested Org-mode + lists. + + For some reason, the =list= output format does not work with the + result drawer: + #+BEGIN_SRC racket :results list drawer +'(1 "hello" (and x y)) + #+END_SRC + + #+RESULTS: + :RESULTS: + - (1 "\"hello\"" (and x y)) + :END: + + Finally, the =table= result format typesets the output as a table: + #+BEGIN_SRC racket :results table drawer +'((a . #t) (b . #f)) + #+END_SRC + + #+RESULTS: + :RESULTS: + | a | #t | + | b | #f | + :END: + + This is clearly very useful for printing states (and hash tables, + more generally): + + #+BEGIN_SRC racket :results table drawer +(st '((a . 1) (b . #f) (c . "hello"))) + #+END_SRC + + #+RESULTS: + :RESULTS: + | a | 1 | + | b | #f | + | c | "hello" | + :END: + +*** A note about printing update function forms + Automatic table typesetting may go in the way of readability for + hash tables whose values are lists, as the following example shows: + + #+BEGIN_SRC racket :results table drawer +#hash((a . (and a b)) (b . (not b))) + #+END_SRC + + #+RESULTS: + :RESULTS: + | a | and | a | b | + | b | not | b | | + :END: + + To tackle this issue, [[../utils.rkt][=dds/utils=]] provides + =stringify-variable-mapping= (with the shortcut =sgfy=) which + converts all the values of a given variable mapping to strings: + + #+BEGIN_SRC racket :results table drawer +(sgfy #hash((a . (and a b)) (b . (not b)))) + #+END_SRC + + #+RESULTS: + :RESULTS: + | a | "(and a b)" | + | b | "(not b)" | + :END: + +** Reading Org-mode tables<> + Org-mode allows supplying tables as arguments for code blocks. + + #+NAME: test-table + | a | "(and a b)" | + | b | (or b (not a)) | + + #+BEGIN_SRC elisp :var tab=test-table :results output drawer +tab + #+END_SRC + + #+RESULTS: + :RESULTS: + :END: + ((a (and a b)) (b (or b (not a)))) + + Unfortunately, the same trick does not work with Racket directly, + because Racket interprets the first elements in the parentheses as + function applications: + + #+BEGIN_SRC racket :results output drawer :var tab=test-table +tab + #+END_SRC + + #+RESULTS: + :RESULTS: + application: not a procedure; + expected a procedure that can be applied to arguments + given: "a" + arguments...: + "(and a b)" + context...: + "/tmp/babel-qkvrRR/org-babel-c4wuju.rkt": [running body] + temp37_0 + for-loop + run-module-instance!125 + perform-require!78 + :END: + + Fortunately, we can easily remedy this problem by creating a named + parameterised Elisp source block which will explicitly convert the + table to a string: + + #+NAME: munch-table + #+BEGIN_SRC elisp :results output drawer :var tab=test-table +(prin1 tab) + #+END_SRC + + #+RESULTS: munch-table + :RESULTS: + (("a" "(and a b)") ("b" "(or b (not a))")) + :END: + + We can now correctly receive this table in a Racket source code + block by threading it through =munch-table=: + #+BEGIN_SRC racket :results output drawer :var tab=munch-table(tab=test-table) +(println tab) + #+END_SRC + + #+RESULTS: + :RESULTS: + "((\"a\" \"(and a b)\") (\"b\" \"(or b (not a))\"))" + :END: + + [[../utils.rkt][=dds/utils=]] has several functions for parsing such strings, and + notably =read-org-variable-mapping=, with the shortcut =unorg=: + #+BEGIN_SRC racket :results output drawer :var tab=munch-table(tab=test-table) +(unorg tab) + #+END_SRC + + #+RESULTS: + :RESULTS: + '#hash((a . (and a b)) (b . (or b (not a)))) + :END: + + Of course, we can use =munch-table= to prepare any other table than + =test-table= for use with Racket: + + #+NAME: another-test-table + | a | (not a) | + | b | (and a c) | + | c | (and a (not b)) | + + #+BEGIN_SRC racket :results output drawer :var tab=munch-table(tab=another-test-table) +(unorg tab) + #+END_SRC + + #+RESULTS: + :RESULTS: + '#hash((a . (not a)) (b . (and a c)) (c . (and a (not b)))) + :END: + +** Inline graph visualisation with Graphviz + Some functions in =dds= build graphs: + + #+BEGIN_SRC racket :results output drawer :var bf=munch-table(another-test-table) +(build-interaction-graph (unorg bf)) + #+END_SRC + + #+RESULTS: + :RESULTS: + # + :END: + + The =graph= library allows building a Graphviz description of the + constructed graph. (Note that you have to install the =graph= + library by running =raco pkg install graph= and require it. The + long property line at the top of this file defining the prologue for + racket source code blocks takes care of requiring =graph=.) + + #+NAME: igraph + #+BEGIN_SRC racket :results output drawer :var bf=munch-table(another-test-table) +(display (graphviz (build-interaction-graph (unorg bf)))) + #+END_SRC + + #+RESULTS: igraph + :RESULTS: + digraph G { + node0 [label="c"]; + node1 [label="b"]; + node2 [label="a"]; + subgraph U { + edge [dir=none]; + node0 -> node1; + node2 -> node2; + } + subgraph D { + node2 -> node0; + node2 -> node1; + } + } + :END: + + You can have an inline drawing of this graph by calling the previous + code block (=igraph=) via a noweb reference in Graphviz/DOT source + block: + + #+BEGIN_SRC dot :file dots/exampleBQNp7Z.svg :results raw drawer :cmd sfdp :noweb yes +<> + #+END_SRC + + #+RESULTS: + :RESULTS: + [[file:dots/exampleBQNp7Z.svg]] + :END: + + Note that the =graph= library draws self-loops as undirected edges. + It also draws double-sided edges as undirected edges (e.g., in the + preceding graph, b depends on c and c depends on b). + +* Local Variables :noexport: + # Local Variables: + # eval: (auto-fill-mode) + # ispell-local-dictionary: "en" + # org-link-file-path-type: relative + # End: