Version 0.4.0 released
Oh my, it’s been a while since one of these. Rest assured, we haven’t been sitting idle - there have been 100 commits to master since our last release. So, let’s get into the changes:
We broke things
Firstly, this is a great opportunity to remind you that Urn, whilst pretty stable, is still in beta. This release has several breaking changes you should be aware of:
#s
and#
are now one function calledn
.- The
#
symbol is used to denote hexadecimal and binary literals. In order to stick closer to Common Lisp, you should now write#x23
and#b011011
when you require other bases. Escape codes inside strings have not changed. - Several pattern matching expressions have become infix. This makes some pattern matching code slightly easier to read. Please refer to the documentation to see what has changed.
Standard library improvements
Pattern matching improvements
As mentioned in the breaking changes section, pattern matching got tweaked a little. There are now support for struct patterns and additional guards. For instance, you can now trivially decompose a structure:
(define my-vector { :x 1 :y 2 :z 3 })
(destructuring-bind [{ :x ?x :y ?y} my-vector]
(print! x y))
and add additional requirements:
(case foo
[((string? @ ?x) :when (= (string/char-at x 1) "f")) x] ;; Find strings which start with "f".
[_ "boring"]) ;; Anything else
Set functions
demhydraz has added functions for a whole host of set manipulation functions. This includes set difference, union, and
probably more. Actually I’m not sure if it’s more. I haven’t checked. Which is fine, as no one actually got this far
through the post. Many thanks to incinirate for his work on improving the performance of the nub
function.
bignum
and bit32
Very many thanks to CrazedProgrammer here for these contributions. Urn now includes a big integer library, as well as a various functions for manipulating bits. I’m sure both of these will prove immensely valuable in the future.
Compiler improvements
Let’s be honest, only I’m excited by these. There have been a couple of minor improvements to the compiler which results in more efficient or smaller code being produced:
Tail recursion into loops
In order to keep a more minimal core language, Urn has no loops. These are emulated via tail recursive
functions. However, these are less efficient than conventional loops and so a solution needed to be found. In this
version of Urn, top level definitions will be converted into loops where appropriate. For instance, consider this
definition of part-all
.
partAll1 = (function(xs12, i8, e1, f3)
while true do
if (i8 > e1) then
return true
elseif f3(xs12[i8]) then
i8 = (i8 + 1)
else
return false
end
end
end)
We do not currently optimise tail recursive functions in letrec
(and so the while
or for
macros), though this is
something you can expect to see in a later release. I’m also working on ways to generate even more idiomatic Lua,
perhaps replacing the above code with a normal for
loop.
Rewrite rules/loop fusion
We’ve also added “loop fusion” as an optional compiler plugin. This allows you to define “patterns” which will get simplified at compile time. For instance:
(fusion/defrule (map ?f (map ?g ?xs))
(map (lambda (%x) (?f (?g %x))) ?xs))
Will rewrite two nested maps into one map over a composition of the two functions. This reduces the number of temporary lists required when using lots of list functions. However, it is not enabled by default as it can technically change the order of operations. This shouldn’t affect most programs, as loop iteration code should generally be pure, but I don’t feel comfortable enabling it by default.
Operators support multiple arguments
This is a relatively small one: All “Lua” operators now accept a variable number of arguments. For instance:
(print! (+ a b c d))
will compile to:
print1((a1 + b1 + c1 + d1))