hello, world. meet scarlet.
(def main ()
^"Hell yeah.")
Status, as of January 12 2007:
Much of what is described here is working today. However, it is in pieces, and some parts are not implemented at all. Expect a public beta by April 2007, with early-adopter downloads and source code control coming much sooner.
This project is not a toy, but intended for serious use in the real world. I run a business, and I use this codebase extensively in my work, so it's important to me that this project moves efficiently and the code be well tested and stable.
Eventually, I want to hire developers to help me work on the code. So it's also important to me that the code be well designed and well documented.
I hope you enjoy this sneak preview as I bring the code up to these standards.
Thanks,
Michal J Wallacecornerhost.com
the framework: scarlet lambda
In ancient times, functional python programmers were shunned, and forced to wear the scarlet lambda as a symbol of their heresy...
Well okay, not really, but that's what I'm calling this thing: scarlet lambda, or scarlet for short.
Scarlet is a very lightweight framework built on top of wsgi:
- based on generators: In wsgi, your handlers yield strings. Scarlet adds to this by letting you yield strings or generators. This allows for a cleaner style, better testability, and also for lightweight asynchronous concurrency via microthreads.
- declarative dispatch: applications are defined as a tree of named callables. Paths in the URL map to positions in the tree. These callables can dispatch on the HTTP method (get/post/put/etc).
- declarative redirects:
- platonic components: generally, your handlers don't know or care that
they are on the web. These handlers must either:
- yield strings and generators
- return None
- throw an exception
- parameter mapping: the dispatch system inspects the handler's signature
and sends the correct data. Special parameters, such as, session objects, database/ORM connections,
and wsgi's
start_response
andenviron
can be explicitly requested. - strongbox: smart classes with runtime type checking and lazy loaded associations
- automatic REST: given a root strongbox, can be automatically generated.
ecdysis: a lisp-like syntax for python
First rule of ecdysis: Stop whining. You don't have to use it.
Anything you can do in scarlet, you can do in plain python syntax. Think of ecdysis as a template system strong enough to write code in.
Features:
- looks like lisp: everything is an expression. Parentheses abound.
- compiles to python: ecdysis and python can call each other freely.
- embedded XML: xml tags are valid syntax. (Thanks, scala!) They define generators that yield tag objects (a type of string).
- mix and match: arbitrarily nested XML tags and s-expressions mean you get cool things like:
- Powerful Templates : like a well formed PHP
- Literate programming : write your code with links, headlines, bullet points, and everything else you get with XHTML.
- cons cells: simple head/tail pairs taken from lisp.
They play nice with recursion. (Gives you
series[1:]
without making a copy.) - macros: yay, macros.
- infix expressions: plain old python expressions when you want them:
# prefix: (+ 1 (int "5") b) # infix: (: 1 + int("5") + b)
- Trailing question marks: I like these for booleans/predicates. (
nice?
maps to pythonnice_p
) - Trailing exclamation points: I like these for imperatives. (
kill!
maps to pythonkill_i
) - group by verb: sometimes it's nicer to add methods from outside the class:
(def MyClass.meth (self etc) etc)
- group by noun: you can still do it the old way though:
(class MyClass (object) { meth : (def (self etc) etc)})
- Alternatives to assignment: Functional programs discourage assigning variables.
Ecdysis introduces
const
andlet
forms to help avoid the equal sign (you can still do normal assignment though). - symbols: you can refer to arbitrary identifiers. You don't have to declare or assign anything if you just need a unique identifier for a concept.
- the do keyword: for when you need an imperative block.
- private prefix:
@at_signs
make for private variables. Also used for@init
,@iter
, etc. These map to the usual python__equivalents__
- explicit main: say goodbye to
if __name__=="__main__":
examples
# return a string. (from main, this means "print")
(def main ()
"hello world")
# yield a string. (same effect)
(def main ()
^"hello world")
# input comes from browser or command line
(def main (name="world" [args] {kw})
^"hello $name"
^"welcome to ecdysis.")
XML style:
<?xml version="1.0"?>
<?def main (name="world" [uri_path] {query}) ?>
<html>
<head>
<title>Hello $(name)</title>
</head>
<body>
<h1>Hello $(name)</h1>
<p>Welcome to ecdysis.</p>
</body>
</html>
future directions
I'm trying to stick to features I personally need for the initial release, and not just to do things just because they're cool. But some ideas are worth keeping, so here's the someday/maybe list:
- proper tail calls
- type annotations
- port the whole haskell prelude
- erlang style processes with candygram
- parrot like virtual machine (since we already have pirate)
- first order continuations
- morphic interface based on wxOGL and sping
- formalize
do
andreturn
around monads
stay tuned
If you would like to get involved in this project, please subscribe to my blog: withoutane.com