#+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: