Wednesday, March 11, 2009

Tropo - a new platform for developing speech applications

Last week, at eComm, Voxeo has launched Tropo, a platform for developing speech applications in a variety of dynamic programming languages. They provide a (synchronous) API to interact with the callers of your application. You can do things like playing prompts, asking questions (DTMF/speech recognition), transfering calls, and so on. All this in your language of choice, without having to mess with VoiceXML, CCXML, low level telephone APIS, and the like.

Tropo currently supports JavaScript, Groovy, Ruby, Python, and PHP. They expect to add support for new languages in the future. And if you follow my Twitter feed, you noticed that they are open to supporting Scheme/Lisp. I even volunteered to help them. What cool guys they are! (It seems I am not the only one who asked about Lisp...)

Now, which Lisp dialect would make most sense on the Tropo platform? Given the state of the Scheme community and the variety of implementations, the answer may not be as simple as you would expect. Here are a few possibilities, with their respective pros and cons.

JVM-based systems

First, there are a number of Lisp implementations on the Java platform: SISC, Kawa, and Clojure. With these implementations, their foreign interface to Java compensates for their lack of libraries.

SISC is a fully R5RS-compliant implementation of Scheme. It can interface to Java, optimizes all tail-calls, fully supports call/cc, etc. It is a mature implementation, but there has not been any new release since the end of 2007. Unfortunately, it does not implement optional and keyword arguments, and does not have a compact syntax for hash maps. I am not sure how elegant code will be in SISC compared to what we can do in JavaScript or the other scripting languages.

Kawa is a less compliant Scheme implementation than SISC and does not seem to have a lot of community support. It does have DSSSL-based optional and key arguments, which is nice, but it does not provide a clean, compact syntax for hash maps natively. But since the reader can be extended, this is not really a big deal.

Clojure, the newest Lisp on the block, may be a good choice. I am not really familiar with it, but from what I saw in the documentation, it supports objects, multi-methods, special syntax for hash maps, optional and keyword arguments, and much more. It does not optimizes tail-calls but, hey, it's a Lisp, not a Scheme. And there seems to have a strong community behind it.

Native implementations

Now, if we now turn to native implementations of Scheme (i.e. not running on the JVM), there are many more choices. I won't list them all, but if we consider the size of their respective community, the clear choices (from my point of view) are PLT-Scheme, Gambit-C, and Chicken. As you know, I have a preference for Gambit-C. It is a robust, fast implementation of Scheme (R5RS). It has very good debugging tools, supports DSSSL-based optional and keyword arguments. The readtable can be modified. Etc. Etc. Add Termite and you have a strong platform for developing amazing next-generation multi-modal voice-enabled applications. But on the down side, it cruelly lacks libraries.

Of course, PLT-Scheme and Chicken do have a lot of libraries, with a language support for using them. Chicken has most of the features of Gambit-C, except good debugging tools (and Termite, of course, which only runs on Gambit-C). PLT-Scheme, on the other hand, does not have runtime debugging tools as good as Gambit-C, but it comes with a great development environment, DrScheme.

And the winner is...

Well, I don't know. From a programmer point of view, I would hesitate between Clojure and Gambit-C. But there may be some other issues that I did not consider, like the architecture of the Tropo platform, the interpreter start time, memory footprint, etc. that would affect how the application could scale. Is there a new interpreter launched for each new call?

So tell me, what would be your ideal Scheme/Lisp implementation on the Tropo platform?

13 comments:

Jonathan Taylor said...

Dominique -

Excellent post!

One note I wanted to make -- Right now Tropo uses a Java standard called JSR-223 to talk with various scripting engines. Amongst the options you list, SISC and Clojure currently have a JSR-223 interface available. So in terms of timing they are the best options; ultimately we can consider other options though.

We look forward to working with you and others to figure out the best way to get a Lisp / Scheme option in Tropo!

Best,

-Jonathan (Voxeo CEO - Coding Executive Officer)

blog said...

I've used SISC and Clojure for production applications and are both good choices. Clojure runs much faster for my code and has quite a number of other niceties that are not available in SISC. I also prefer Clojure java interop.

Anonymous said...

That's sorta weird. Festival from CMU used a scheme dialect as well. You configured it in scheme and even added new voices and code for those voices in Scheme

Dominique Boucher said...

@anonymous What's weird in that? The GIMP also comes with a Scheme interpreter, AutoCAD comes with AutoLisp, and so on. Scheme/Lisp (not Common Lisp) makes a very good scripting language for non programmers. Its syntax is easy to learn, there are only a few special forms.

Dominique Boucher said...

@Jonathan Of course, if you already use JSR-223, Clojure or SISC is the way to go! No doubt about that.

Jonathan Taylor said...

@Dominique -

At first glance Clojure is ideal due to its syntax for hash maps. Possibly important due to extensive use of hash maps in Tropo. What would the closest equivalent look like in SISC?

-J

Dominique Boucher said...

@Jonathan

I took a closer look at Clojure yesterday and I cannot agree more with you. There is nothing equivalent to the hash map syntax in SISC. A bit of macrology can get us closer, but this would not be as elegant as the JavaScript/Python/Clojure syntax.

Also, Clojure seems a more pragmatic, modern Lisp language (it's neither Common Lisp nor Scheme but a Lisp of its own). And as @blog noted above, the Java interface is clean and very simple to use.

sergio said...

One other big advantage of clojure is that it seems to attract both the java and the lisp communities.

For the record, there exists a java implementation of Common Lisp (ABCL) that supports the JSR 223:

http://common-lisp.net/project/armedbear/

Anonymous said...

I have done a proof of concept with SISC for an enterprise quality Web application using SISCWeb but found the performance was too poor. The framework was good and interfacing to Java was acceptable although not pretty.

I've also looked at Clojure but ruled it out because it doesn't support first class continuations which, for me, has to be a pre-requisite for a web application. After all we want to improve on Java and not just needlessly add to the technology dependencies.

It seems at the moment, there isn't a Scheme that supports first class continuations and has performance to match current J2EE applications. It's a shame that Gambit doesn't have a FastCGI and database interfaces that don't break the threading model.

Dominique Boucher said...

Anonymous,

I totally agree that SISC is way too slow for serious web applications. That's why I chose Kawa many years ago.

In the case of Tropo, I don't think continuations are a must. They may simplify the implementation of the API, of course. But I don't see them as a pre-requisite. However, full tail-calls optimization is another story. Being able to write in continuation passing-style (CPS) could lead to interesting new ways of developing and exposing reusable dialog components.

Jonathan Taylor said...

@Dominique - Forgive my ignorance (if you ask a question about ObjectPascal I have the answer...) I assume Clojure supports CPS?

Dominique Boucher said...

@Jonathan
CPS is a writing style, not a feature of the language. In this style, your functions never return, but instead call other functions in tail-call position to handle the result. So the language has to optimize full tail-calls in order to use that style effectively. Otherwise you will have bust the stack rapidly.

Unfortunately, Clojure does NOT optimize tail-calls...

The Careful Programmer said...

@Dominique

Clojure does optimize some tail-calls, but it has to be explicitly stated in the code.
Clojure Recursive Looping

There is recur for self-recursion and trampoline for mutual recursion.

There are also lazy sequences, which can eliminate the need for recursion in some cases. The Functional Programming chapter of the book Programming Clojure gives good examples. I'm sorry I can't explain it better; I'm still a Lisp newbie 8)