What sucks about Scheme
« Tuesday, September 17, 2013 »

Scheme

Not that I dislike Scheme at all, but it's kind of funny to hear how scheme is great but we rarely find any proof of it. It seems to be a problem that most Lisps are facing nowadays. I heard that, once upon a time, lisps were very popular and taught in school/universities. Recently, the MIT moved from teaching Scheme in Computer Science courses to python because python was a language for human being. We can ask ourselves what did go wrong. How did Lisps came from “awesome” to almost “esotheric” language.

During the last year, I got more and more interested into learning Scheme and Lisp. I often read how cool is the language. I have to admit that I love Scheme for its flexibility, I feel that anything can be done with it and if not, we could write a program that will rewrite itself in order to acheive what a human can't do. The macros are incredible and so on. Coroutines can be implemented natively using call/cc. All of this seems a bit complex at first but makes me feel that other languages are lacking thoses features. The macros in C are a joke, the metaclass in python is great but makes the program much more complex than a macro expension in Scheme.

So why does Scheme suck?

Well Scheme in itself doesn't really suck as a language, but as a language to make things done it fall short on other languages. Since the core of scheme is so small, it is one of the easiest language to implement. For that reason many implementation exists. Unfortunately, most scheme seems to be incompatible between each others. If you write a scheme program for chicken, chances are that it will not work on Racket. One simple exemple is that we can search for documentation on how to append an item to a list. From what I found, there are at least those ways to do it.

Append creates a new list and doesn't change listA and listB

1
2
(append listA listB)
(list-append listA listB)

Append! that changes the list (you need to import list-utils in Chicken scheme)

1
2
(append! listA listB)
(list-append! listA listB)

As incredible as it might be, lists are part of scheme but there is no way to append item to lists in a standard way. It's possible that one or the other variant will be present. You can always roll your own with set!, cdr to change the list. But I'd expect appending item to a Lisp should be a fixed problem in 2013.

I recently watched a video about r7rs-small by John Cowan. I guess this video is really insightful in what went wrong with Scheme development for the last 20 years. The unanonymous vote that prevented new things to get added to scheme probably did make things slow. And hopefully, Scheme development will be great in the future.

I'd say that one thing that scheme lack is standardization. Scheme doesn't have a main repository for extensions written in Scheme. Let say, that srfi is the standard packages that should be integrated to any scheme. Any SRFI implementation shouldn't depend on scheme specific things, it means we should be possible to download any srfi implementation and load it in any scheme that support for example r5rs or the scheme revision it was built for. I'm only aware of the chicken scheme egg repository, it working great but implementations are still specific to chicken scheme. There is no library yet, the r7rs revision of Scheme promise libraries but without repository I'm pretty sure it will fail for some time.

Naming convention for packages, currently packages are named after the srfi that was used to write it. Requiring (require srfi-32), doesn't tell much on what we are actually requiring. Most of those problems should be solved in the future of r7rs but currently it kind of suck. In 2013 there is no standard way to do date arithmetic in scheme. Add/remove and doing time deltas doesn't seem to exist or is deeply hidden in undocumented part of the internet.

What should be done

  • Standardize libraries that solves common problems, merge codebase to make them more complete if needed
  • Create libraries repository and possibly a package manager that could be used for different scheme
  • Name srfi packages in a more straight forwardly way.
  • Only one stanrdard way to require/import package (having implementation specific imports prevents package from being used everywhere)

The future ?

It's been already two years since the video of John Cowan about r7rs-small. It's hard to find any information about r7rs-large since most of what the working group 2 has to do depends in some ways on what the working group 1 is supposed to do.

In all honesty, I believe that separating the work in two groups isn't helping much. If people want to build a small scheme and a larger scheme, it's quite similar to the builtins of python and the python directory. Anything that falls into pypi should be quite standard. It is also possible to tag some package as compatible with python3 or python2 only.

Designing a package in scheme could be done in a similar way.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
(import package)

(package
  (name "json")
  (version "1.0.1")
  (description "A package to parse and dump json objects")
  (requires
    (srfi '(1 4 69)))

  (author "Someone <som@at.com>")
  (maintainer "...")
  (license "gpl")
  ...)

This is an example of how I'd expect it to look like. Chicken scheme is using a file.meta to handle packages.

Library/Packages and import mess in Scheme

Just in chicken scheme, there are so many ways to import an actual module. Modules are defined within the code instead of a file being a module. For that reason, it is quite possible to find multiple modules within a single files. Don't ask me why but they've done it that way.

Just to give an idea, you can load “code” like this in chicken:

import
use
load
require
require-extension

Each method takes different parameters and are slightly different from each others. It's hard to say how many function it exists to do almost the same thing. For example: import seems to be useful when used within a module. The use function is a funny one, it seems to be calling require-extension and import. In my own opinion, all of these function should be replaced by only one and some internal ones to load compiled libraries or scripts. Internal function should be implementation dependant while the public interface should be standardized for every scheme. A Scheme module shouldn't be able to call anything else except the public interface to prevent some module to use “hidden features” that aren't cross compatible with other scheme interpretator.

comments powered by Disqus

Copyright © 2015 Loïc Faure-Lacroix