muSE - an embeddable scheme dialect

Hi all,

My pleasure to announce that my company has allowed me to publish muSE - an embeddable Scheme-like scripting engine we use - under a liberal open-source license. The first place I could think of was LtU, so here it is.

Code is available here.
I'm documenting it gradually in this blog.

From a language design perspective, nothing very dramatic, though some lisp afficionados might be interested in some novel/experimental features like -

  • (Sort of) first class macros
  • Ability to choose dynamic or lexical scoping for functions/closures.
  • Use of pattern-matching bind in let, case and fn (read "lambda").

Enjoy!

[EDIT] Code hosting site and blog site address have changed.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

oooooooo

I like it!

I've posted more

Wonderful!

This is great stuff!

I am a little confused about how lexical scoping works in muSE. If a binding for a variable is not found in the lexical scope, does it fall back to dynamic scoping?

> (define f (fn (x) (+ x y)))

> (f 2)
Error: + can only work with integers and floats. Given type MUSE_SYMBOL_CELL.
2
> (let ((y 3)) (f 2))
5

Thanks,

-K

Virgin symbols in muSE have

Virgin symbols in muSE have the property that they evaluate to themselves. Therefore when creating the closure "f" in your example, the symbol "y", which is undefined, evaluates to itself.

So yes, you're right in that undefined symbols are considered dynamically scoped. This allows muSE to accept named forward references, which include recursive functions.

For the large part of muSE, I've used the cheapest, simplest, easiest technique I could think of ... and now and then the coolest :) ... and a general principle is "never really prevent anyone from doing anything unless you absolutely can't satisfy them". For example, you can use an expression like -
(1 2 3 4 5)
It'll simply treat it like
(list 1 2 3 4 5)
though it'll warn you about it. I've found this feature useful when using muSE as a file format.

muSE generally bares its

muSE, in general, bares its internals unless it doesn't make sense. You can use (print f) or (write f) to see what f actually does. You can then compare it with a definition using fn:.

Update: Polymorphic built-in higher order functions added

Hi all,

I've added (to muSE) map, reduce, join and collect which work with lists, vectors as well as hashtables.

Any thots on these? In particular on the collect function - whether its design is general enough to handle a broad class of iterations. The rest are rather straightforward and I'll probably leave them as they are.

I'm toying between the simpler "collect" and a more general list comprehension implementation.

'the' and 'it' - simple context sensitivity in muSE v437

muSE has grown quite a bit since my original post here and I've been using it as a ground for my language design experiments (in addition to shipping products with it). I've added a couple of primitives 'the' and 'it' in v437 aimed at dramatically reducing the need for local variables used to store temporary results. I've found it very useful on the REPL and I think it is very useful when working with imperative code in particular. I'd greatly appreciate thoughts from LtU folks on this language feature.

Clever use of semantics

Nice idea with the and it. I hope you find a way to speed it up by 8x! :)

I think that would be nice in scripting languages like Applescript, going to suggest it to Apple.

I like the way AppleScript

I like the way AppleScript code looks and you're right in that this way of looking at the and it might add to its current elegance. I find it very handy in the REPL to recall earlier results rather than use $0, $1 or some warts like that :) Here is one particular form I've taken a liking to -

> (open-file "somefile.scm" 'for-reading)
> (read (the open-file))
.....do something with (the read)
> (close (the open-file))

dynamic-wind might help

dynamic-wind might help ;-)

i'm going to keep this trick in mind :) interesting perspective - wonder what other natural language cues (contextual or not) make sense. for example, declension in russian allows arbitrary ordering of terms, which shows up in ways to show infix vs prefix operators. then again, connotation does change depending on ordering...

Fusional languages are hard to lex

Another trick from Russian (and many other languages, old forms of English included) is to have personal pronouns of different genders applicable to inanimate objects - thus, instead of just "it", one can have "it", "she" and "he" (in some languages more). Even in modern English, boats and other objects can be "she" :)

This trick gives you more short forms, but in a quite ad hoc way - quick, is "find" he or she? One may replace genders by types - but this is essentially another form of "the", or kinds - Perl funny characters come to mind. @it anyone? :)

Returning to the general idea of borrowing ideas from natural languages - I think isolating languages are closer to what is feasible for a PL given the state of art (and the expectations of the community). Next are agglutinative languages, which only involve a bit more lexing. Modeling a syntax of a PL on a fusional language (Russian being quite typical representative) is a controversial idea, though (refactoring without a specialized tool becomes close to impossible - you cannot search and replace, for example).

I remember programming in BASIC with cyrillic keywords, but that was definitely far from Russian language :)

Declension might just be a

Declension might just be a special case of keyword arguments, no? For example -

; pseudo code
(open a:file called:"blah.txt" for:reading)
(print on:stdout (expr 3 of:(the open file)))
(close (the open file))

As for dynamic-wind, it will be nicer in muSE once I implement capturing (the ..) expressions within closures. You can write it the following way -

(try
 (do (open-file "blah.txt" 'for-reading)
     (finally (close (the open-file)))
     (read (the open-file))
     ; ... do something with (the read)
     ))

and the close will be evaluated when the try block completes - normally or exceptionally.

edit: ExceptionHandling in muSE - try, raise, retry and finally.
edit: The above (try ...) code will work in v454.

video editing and Scheme

my company has released a public beta sdk that lets you create video editing styles in muSE (which is a Scheme dialect). muSE has been in use in muvee for over two years and this is the first time the informal DSL we use for visual style specification is being opened to the public.

Here is the googlecode link -

http://muvee-style-authoring.googlecode.com

Looks nice! Did anyone look

Looks nice! Did anyone look at the tutorials and has opinions to share?

looking for feedback

Btw, I posted about this on the PLT mailing list too, it being a Scheme-specific community.

.. and a big yes to comments! I'm looking for feedback to improve the DSL itself and the documentation and tutorials, and suggestions for tools built atop the DSL to make this kind of "programming" more accessible to artists. Pointers to other work of this kind are also welcome. Even for newbies, it is just plain fun to write scheme code for visual effects in a 3D environment as opposed to, say, the fibonacci function ;)