#S - Scheme for the .NET framework

What is it?

#S (sharp.scheme) is a port of Peter Norvig's Silk written in C# that runs on top of the NET framework. The current version is 0.38. It implements all of r4rs except some limitations. The goal is to provide a simple, portable and embeddable interpreter that expands upon the original, while remaining hackable and small. Additional support for r5rs standard procedures and SRFI libraries is planned, as well as integration with the .NET framework libraries.

Motivation

I've been always interested in programming languages implementation. While writing other simple interpreters, my research led me to a growing interest in multi-paradigm and functional languages like Haskell, Ocaml, Scheme or Lisp. At some point i've decided to try my hand and implement an interpreter for one of them.

Scheme was an obvious choice.

  • It is mature. Was developed by Guy L. Steele and Gerald Jay Sussman in the 1970s.
  • Has a minimalist approach to programming, with very concise and practical notions.
  • It has a well defined standard, the revised (N) reports on the algorithmic language Scheme.
  • It sports interesting features, like closures, continuations, tail recursion, a powerful macro system or lexical scope.
  • It is suitable for research, scripting, education or as an embedded extension language in applications.
  • Porting Silk

    Silk is a Java implementation of Scheme written by Peter Norvig in 1998 and subsequently adopted by Tim Hickey and Ken Anderson. The latest version from Norvig is 1.4 while the latest full-featured version is not hosted at Sourceforge and dates from 2006.

    Porting it to the NET framework offered some great opportunities. First, while there is pretty good implementations of Scheme for Java this is not the case with .NET. As far as i know there is Kawa, Sisc, Sixx, BDC Scheme, SP, PS3I and Mscheme for the Java VM while there is only IronScheme and Common Larceny for the CLR, and while both are really awesome, their source code weight is about 7 MB and 10 MB in size (that's a lot of semicolons!) respectively, so they are not easily embeddable or hackable.

    Furthermore porting Silk is a great exercise on learning more about Java and Scheme, (i've used C# before) and it allows me to take an insight in how the program evolution procceeded from the first version to the latest one.

    What went right ?

    Mostly everything. I've tried to keep things as simple as possible. The rationale is that the interpreter should be easy on you as the user and easy on me as the developer. The full r4rs procedures are working and the interpreter behaves almost exactly as the original. Norvig's code reads like prose. It still fits on 50 KB as Jscheme does. :-)

    It took about 25/30 hours to port it. If this seems too long, i'm usually very picky with code readability and how the classes are organized. If it seems too short, i've used some tools wich made my life easier, like refactoring on VS 2008, Vim macros, or Visual J# to debug the original code.

    Deviations from the original and design

    Changelog as of 0.38a

    User visible:

  • Closures return it's full args/body when represented as strings.
  • Null arguments append "none" on warnings.
  • Non-symbols can't be defined. This was only handled for set! in the original.
  • Error messages are usually more explicit and detailed.
  • Binary, Octal and Hexadecimal number notation is correctly parsed.
  • Representing #\n and #\s no longer results in a unbound variable error. #\Tab was added.
  • "define-macro" added. The (macro (args) body) syntax is still allowed.
  • "truncate", "ceiling" and "floor" added to the environment primitives.
  • "define-up" and "set-up!" are extensions that work like Tcl's upvar procedure.
  • Internal:

    I've followed the original code whenever possible. Still, i've made some changes. The big switch statement with the opcodes made me want to shoot myself on the foot so i've changed it to work with function delegates instead. For efficiency the linear lookup of symbols is gone in favor of using HybridDictionaries. This change makes the interpreter a lot faster.

    The Primitive class is now abstract and there are three new files, namely: 'ss.r4rs.cs', 'ss.r5rs.ss' and 'ss.rxrs.cs' wich hold the primitives for r4rs, r5rs and extensions respectively. This should make it easy to extend it with new primitives.

    The bootstrap proccess works by loading some few scheme primitives at runtime, but most of them are defined in the C# code. Those files are inside the executable so that this is completely transparent by using the embedded resources feature. The final sharp.scheme.exe file weights at about 50 kb. It can also be compiled as a dynamic link library accesible from any other .NET program.

    Future roadmap

  • Internal changes to the evaluation engine will happen to ensure it gets faster. (multithread) (optimizing closures)
  • I'll look into it to add all r5rs standard procedures.
  • .NET integration. It should be fun to have access to the whole set of libraries.
  • SRFI support.

  • Carlos Daconcepción archville.mailbox (at) gmail.com