Monday, April 11, 2011

Using Scheme with Babel

As I mentioned in my Blogging and Babel post, Babel supports many languages that produce things other than pictures. Naturally, I wanted to try it out with Scheme. Here's a toy problem that demonstrates some of the things you can do.

Suppose we have some input arguments in a table

12345

and we want to calculate the values of various functions of those arguments. We start with the definition of the input table and a Scheme source code block:

#+tblname: input
|1|2|3|4|5|

#+source: func-tab
#+begin_src scheme :var args=input :exports results
  (define fib
    (lambda (n)
      (let fs ((n n) (a 0) (b 1))
        (if (zero? n)
            a
            (fs (1- n) b (+ a b))))))
  
  (map (lambda (n) (list n (* n n) (expt 2 n) (fib n))) (car args))
#+end_src

Babel delivers tables to Scheme as a list of rows so the input to the code block is ((1 2 3 4 5)). Likewise, if we want a table as output we should return a list of rows. That should help you understand what the code is doing. As you can see, the map produces a list of rows where each row is (n n2 2n fibn). All of the functions except fib are built in, but I included fib to show that you can define functions in the code block if you need to.

Notice that we named the input table with the #+tblname: input line just before the table. Similarly, we named the code block with the #+source: func-tab line; we'll use that name a bit later.

When we run the func-tab code block by typing C-c C-c with the point in the block, we get the output table:

1121
2441
3982
416163
525325

The table gives the correct results but suffers from the fact that it doesn't have a heading telling what each column is. We can fix that by pushing the list ("n" "n^2" "2^n" "fib_n") onto the front of the result of the map function in the func-tab code block but then we end up with

nn22nfibn
1121
2441
3982
416163
525325

which is better but still not what we want. The problem is that there is no hline under the headings so when we export the table to html no <th> tag is generated and we can't use CSS to format a nice looking table. What we want should look like

| n | n^2 | 2^n | fib_n |
|---+-----+-----+-------|
| 1 |   1 |   2 |     1 |
| 2 |   4 |   4 |     1 |
| 3 |   9 |   8 |     2 |
| 4 |  16 |  16 |     3 |
| 5 |  25 |  32 |     5 |

in Emacs. There's no documentation on how to do that but by trawling through the Org-mode mailing list I found some hints. At least in elisp and Scheme you can represent the hline by including the symbol hline as a row where you want it to appear. Thus we want to push

'("n" "n^2" "2^n" "fib_n") 'hline

onto the front of the result of the map in the func-tab block. We could do that by adding the code to the func-tab block but I want to demonstrate something else instead. In general, if we want to post process output from a block, we can merely call the block from our post processing code—that's why we named the func-tab block.

In our case we merely want to push a couple of new rows onto the result of the func-tab block but we could do any processing at all. To see how that works, we define a new block to do the processing:

#+begin_src scheme :var tab=func-tab :exports results
  (define cons2
    (lambda (a b c)
      (cons a (cons b c))))
  
  (cons2 '("n" "n^2" "2^n" "fib_n") 'hline tab)
#+end_src

Notice how we set our input, tab, to be func-tab which causes this block to use the output of the func-tab block. Now the neat part is that when we get ready to export to HTML we evaluate only this last block. This, in turn, will cause the evaluation of func-tab but no intermediate table will be produced so we get only the final desired result. If for some reason we want the intermediate results too, we merely evaluate the func-tab block directly.

Another nice feature of this method is that the blocks can be written in different languages. In fact, the final code block was written in elisp until I discovered that the same hline trick worked in Scheme.

When we evaluate the last block and export to HTML we get our final result. I've added at little CSS sugar to show how we can improve the output when we have an actual <th> … </th> heading.

nn22nfibn
1121
2441
3982
416163
525325
I'm still learning about Babel and will probably post about it again as I learn new things.

No comments:

Post a Comment