23 January 2019

Scheme Runtime and Editor Choices

Last month I wrote about my journey into the Scheme programming language, its standards and complete list of its special forms and functions. Today I want to describe some Scheme implementations I used as well as lightweight tooling to get started.

Scheme Runtimes
A nice thing about Scheme is its availability. There are many Scheme implementations and often many are available on different platforms. I started out using Gambit Scheme. I do not remember why I chose Gambit. It is certainly not the most popular one, which - according to questions on StackOverflow - is Racket. (On the other hand, Racked is much more than Scheme.) I guess I took what came up in one of my early Google searches.

if muybridge could bark (maybe a long shot but hey this dog is running)Gambit Scheme
Gambit is an R5RS compliant Scheme written in C. It is easy to install, mature, stable and under active development on GitHub. It is available for MacOS and Windows. Download it here. Besides the standard functions, it offers some SRFI- and many non standard ones for IO, threading and synchronisation, additional data types like signed and unsigned integer vectors (SRFI 160) and much more. Gambit comes with both a Scheme interpreter (gsi) and a compiler (gsc). The compiler transpiles Scheme into C which is in turn compiled using the GCC infrastructure (which must be in your PATH). The pre-compiled binary interpreters can be deployed as single EXE files. Yes, now I am able to write low level C code without knowing C. Win!

Gambit works well and I had no problems getting started. I recommend it to get started. While playing around with it I followed the same approach as last time and scraped the documentation for all available functions. Only later I found these lists provided by Gambit itself: R4RS and R5RS as well as all forms and functions provided by Gambit. There is a lot of documentation, which I still plan to read.

Then I found IronScheme. Like IronPython and IronRuby, IronScheme is a Scheme implementation based on the Microsoft DLR (i.e. the Dynamic Language Runtime). Most of its code just delegates into the CLR (i.e. the .NET Common Language Runtime). For example string-contains? is defined as
(define/contract (string-contains? str:string sub:string)
  (clr-call String Contains str sub))
IronScheme supports compilation, too. Now I can write native Windows applications without knowing anything about .NET. IronScheme is (by its own definition almost) R6RS compliant. Because of the added complexity of R6RS modularity I have not used it as all my Scheme work consists of toy projects. For real world application modularity would be the way to go.

I could not find any pre-build releases of IronScheme. To get the latest build go to its AppVeyor page, select the first build job (probably Environment: FX_VERSION=v2.0) and open the Artifacts tab. After downloading and unpacking the ZIP, the Scheme library code has to be compiled with ngen-all.cmd and echo (compile-system-libraries) ^| IronScheme.Console32-v2, yielding 10MB of DLLs.

Kawa Scheme
There are several Schemes available for the JVM (i.e. the Java Virtual Machine). One of them is The Kawa Scheme language which supports R5RS, R6RS and R7RS. I have not used Kawa. And of course there is Clojure which is a dialect of Lisp and somehow similar to Scheme. But Clojure lacks tail-call optimisation, which is required for Scheme implementations.

Mobile Devices
There are Schemes for mobile devices, too. Gambit builds a version for iPad and Android has several Schemes, e.g. Simple Scheme. So if you ever have been away from your computer and thought, "Boy, I wish I could be writing Scheme code right now" - well, now you can!

A lightweight process supports learning
I still have not read much documentation on Scheme besides SICP which uses basic language concepts so far. I am just playing. The lightweight process I am following is keeping up the fun and supports my learning:
  • Scheme has this minimalist design philosophy. I really like its simplicity. I am never stuck on syntax, reserved words or edge cases. And there are no semicolons. ;-)
  • R5RS is the Scheme to start. It is the most widely implemented standard and most documentation and StackOverflow answers apply.
  • The Scheme runtime must be easy to install and should not mess up my system.
  • I favour runtimes that are available for different architectures and operation systems so I can use the same runtime on different machines, e.g. on my main x64 workstation, my legacy x86 netbook and even my tablet. Especially when having fun with learning, the device should not be limiting me.
  • An interpreter usually starts faster than a compiler which is important for my trial and error approach. The Gambit interpreter starts fast and I use its REPL to explore the language often.
  • A lightweight editor. Emacs would be the traditional editor operating system to work with Lisp languages and I know at least one Clojure developer who uses it. I have never used it and while getting into Emacs would be a cool and fun thing to do - long overdue according to my learning list - I do not want to post phone my Scheme experience. Any text editor should do. I will talk more on editors later.
Colour Out of FocusUltraEdit Syntax Highlighting and Tool Integration
I met UltraEdit 15 years ago and still use it as my main text editor. I guess I am old-fashioned as my version is 8 years old. Before going full scale with Emacs, I wanted at least some syntax highlighting in UltraEdit. Adding a configuration for syntax highlighting is simple (and I have done it before.) With the complete list of forms and functions I created a UltraEdit wordfile for R5RS/Gambit Scheme and one for R6RS Scheme. As soon as UltraEdit knows about the structure of Scheme, it provides code completion and shows all functions defined in the current file.

In the tool configuration I declared a tool to run the current Scheme file (command line gsi "%f" with working directory %p). UltraEdit has a shortcut to select groups of parenthesis (CTRL-B) which is very handy when working with lots of parens.

The next thing I missed was auto format. Formatting is important to keep code readable. Automatic formatting is important, because it saves work and it is easy to overlook a missing blank or newline. So I created my own Scheme-Formatter.

What about a real IDE?
Eventually UltraEdit became too "small" for my Scheme project. It works well for single file scripts but I the navigation between files is limited. So I switched to Visual Studio Code with the vscode-scheme extension. Code is nice because the navigator enables fast navigation and version control is integrated. I can commit and diff without switching windows. I mostly use search and replace across all files as it is my main refactoring tool. In the end, Code is just another editor. It is not an IDE like Eclipse or IntelliJ is for Java. The Scheme extension provides syntax highlighting but the editor's auto indentation always screws up the formatting.

Restarting development with a new language in a new environment was amazing. As the project grew I (obviously) had to learn more and more things. For example - because of the size of the code - the next thing I wanted was to navigate to the definition of a function. Enter Ctags. Ctags supports Scheme out of the box and both UltraEdit and Code are able to use the generated tags file. Of course Emacs does as well. Maybe I need to go for Emacs after all.

No comments: