There have been a number of conspiring factors that have led me to taking another look at Guile, the GNU Scheme programming language:
- hearing about Guix, a Linux distribution from FSF using Guile as a configuration tool
- the possibility of re-writing my neoleo spreadsheet program in a high-level language
- frustration with trying to set up bluetooth on Linux
My neoleo program is a fork from GNU’s oleo program. It was originally written in C, and I have begun migrating it to C++. I noticed that the code could be simplified considerably if it was written in C++.
For example, the cells in the spreadsheet are stored as a list of lists, implemented in C. The source file that handles the list is 1067 lines long. Most of this should just go away if I used C++’s map standard object. It’s not remotely that straightforward, of course, because the use of cells permeates the whole of the project. So replacing that file amounts to rearchitecting the project.
There are also other re-engineering tasks that look worthwhile. For example, when you type in a cell formula, neoleo has to parse it. It byte-compiles it, and decompiles it when necessary. But why do that? Why not just store the AST, and use that? No need for byte compilation or decompilation.
Memory allocation is extraordinarily difficult to reason about in the project. I am sure that it could be done a lot better in C++.
It struck me that C++ is a poor choice for the project, though, in two respects:
- the data type of a cell is inherently polymorphic. Maybe it’s a formula, maybe it’s a number, maybe it’s a string. It’s very awkward to represent algebraic data types (aka Sum Types) in C++. C++17 is not available on many of the slower-moving distros, and having played with the variant type of C++17, I’m not sure I am happy with it. I am wondering whether using an object to represent an variant is such a good idea. My own theory is that they require syntactic extension to the language in order not to seem like a massive kludge
- neoleo provides a lot of formulae and functions. Inevitably, functions have different “signatures”, meaning that you have to pack and unpack arguments. It would be nice if you could just apply arguments to a function.
So, although I think type safety is a useful, desirable and important feature in C++ in general, it is a poor fit for spreadsheets, which inherently involve a lot of polymorhism.
So it got me to thinking that maybe I should, perhaps, go “even high up the food chain” to a language much more suited to this: a language like Scheme or Lisp, for example.
Enter Guile. It even has a parser, which is useful. Now cells can be stored in a hash table, and a parse of user input is much simpler, and its AST can be stored directly. A lot of code simply disappears.
I came across SRFI-119 (“wisp”), which means you can remove bracketing from expressions. So, instead of writing (display “hello world”), you can type display “hello world”. If you’re interested in getting it running:
wget http://www.draketo.de/proj/wisp/srfi-reference.scm mv srfi-reference.scm srfi-19.scm guile (load "srfi-119.scm") (use-modules (wisp-scheme)) (define life 42) (eval (car (wisp-scheme-read-string "display life")) (interaction-environment)) ;;; output => 42
In the end, I’m not sure it’s quite suitable for what I am after. I think I need to write my own parser. It’s close, but maybe not quite what I’m looking for.
This also got me to thinking about how I might use Guile for system administration work. Text files for configuration are difficult to automate. They’re easy to edit, but difficult to automate. What is needed is a text editor that understands the semantics of the particular configuration file.
So I had this idea as a kind of “object-oriented” shell, and a text editor. Neither of these ideas are new, but I don’t think they’ve been implemented in a way that realises my idea.
So my next step would be, I think, to write a text editor in guile. I am aware of the Guile Emacs project, but that’s not quite what I’m after. I’m after an editor in the style of “ed” (maybe “ex” … or really ambitious: vim) rather than emacs.
So it will be a minimal subset of “ed”, but programmable. It is different in conception from vim in that it has a “proper language” underpinning it, and uses “embedding” as opposed to “extending”. So the whole thing should be much more composable with other tools.
You would then have other modules, completely independent, that understand how, for example, the “/etc/hosts” file works, and it could use the text editor to edit that hosts file. So you could do something like have a separate file in a git repo containing the network file address of your LAN, and invoke a guile script that edits your hosts file to recognise the the new machines. You can add and subtract machines, and the script will be sufficiently intelligent to know how to edit the file.
Now, you could do all this manually, of course. But with my proposed methodology, you could easily bootstrap a new system.
Anyway, that’s the big idea.