I’m a great fan of the Yeti programming language, a JVM-based functional language which I think offers an irresistible combination of easy, fluent syntax with rigorous typechecking and good interoperability and performance.
Yeti is written by one developer, Madis Janson. I dropped him a note with a few questions about the origin of and his aims for the language, and he gave permission to post the conversation here (thanks!).
Chris: I’m interested in how you came to write Yeti…
Madis: The biggest reason was just having an idea one evening about basic syntax, which kind of seemed to fit.
C.: Which syntax was that?
M.: From October 2007…
foo = expr; // binding - define foo foo arg1 args... = expr; // binding - define function foo { binding; bindings } // structure literal [ expr; expr... ] // list (expr or binding; expr) // sequence foo.bar // structure field ref foo bar // application +,-,*,/ // arithmetic // module is simply constant value // data types - primitives, list, structure, function
Basically only thing that has changed in this core language is ‘,’ instead ‘;’ in list and structure literals (and this was a very early change).
I had previously thought quite a lot about type systems and inference, so I had ready ideas to try about that too. So I just decided to try to write it and look what comes out.
C.: Did you have a particular field of use for it in mind?
M.: At the time I was mostly working on one enterprise Java system, probably Yeti is somewhat influenced by the problems I had at hand there. So Java web applications are probably the nearest to the particular field. At the same time it’s heavily influenced by perl text-manipulation capabilities.
Some influence was probably Scala, in which I was a bit disappointed. It can be said that Scala type system is genius (in mixing Java object hierarchy with expressive functional typesystem). The down side is that the complexity is somewhat overwhelming and the core language/library provides about ten roughly equivalent ways for doing anything (exaggeration, but still it feels like this). Scala code tends to be clever and compact, but not particularly easy to read (or even write). In the end I think, that trying to meld multiple radically different typesystem realm in this way is not worth the resulting complexity and confusion. Yeti took another approach in trying to isolate the Java interfacing – there are two typesystem subsets, “Yeti types” and “Java types”, and while working with Yeti types the Java typesystem can be ignored.
In the end basing Yeti on JVM at all has been blessing and curse at once, but it’s too late to change it.
C.: What aspects of the language itself (as opposed to implementation details) are influenced by limitations of the JVM?
M.: Yeti does tail call optimisation only inside single function (using JVM goto instruction) since JVM doesn’t support it. Type classes could have been implemented on JVM, but when I started writing Yeti, it seemed too complicated.
C.: I like the approach you took with the typesystem and the small number of core types in Yeti. One intriguing thing is the fact that there’s only one number type. Is that a question of necessity because type inference would be too fiddly otherwise, or a design decision?
M.: Two reasons. It allowed to avoid type classes altogether, and any complexity associated with implementing them. Multiple number types require either type classes for overloading, or separate operators for each numeric type. OCaml does the latter, which is kind of ugly imho.
Second reason is, that even with type classes and overloading, the strictness of HM style typesystem leads to requiring to use functions like float_of_int/fromEnum/toIntegral whenever the value is of “wrong” type. This usually won’t make the code any better and just clutters it. Since Yeti goal has been more simplicity and getting out-of-the way than being fastest language on the earth, it made sense to treat any kind of number as being just a number. The numeric tower system has been copied from Scheme.
Yeti tries to show, that you actually can have scripting-language style simplicity together with static typing. I think it has mostly succeeded in this, although there have been problems (mostly with error messages). You can prototype quite like in perl or python, and then just write type declarations wherever they seem useful for reading clarity. Differing with optional static typing, the code without declarations is still checked for being correctly typed – this is important if you want to rely on static typing with larger code base.
It’s not enough to have just experimental language to prove that this approach works – the language itself must be complete and stable enough that lot of complex code can and will be written in it, and experience gained through it.
That’s one of the current goals for maintaining Yeti, having a working proof that the distinction between dynamic and static languages is meaningless, that you can have the cake and eat it too (have most of the type-related errors discovered early with very little extra effort by developer, while retaining most of the relative simplicity of dynamic typing).