tag:blogger.com,1999:blog-33448912592341508082024-03-13T12:50:01.847-07:00Lux DevlogEduardo Juliánhttp://www.blogger.com/profile/16436429020274670468noreply@blogger.comBlogger5125tag:blogger.com,1999:blog-3344891259234150808.post-31761748421912391242016-01-21T23:57:00.000-08:002016-01-28T06:12:26.179-08:00Monads, I/O and Concurrency in Lux<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">Hello, and welcome to the 5th entry in the </span><b style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">Lux Devlog</b><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">, a blog dedicated to the design and implementation of the </span><i style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">Lux Programming Language</i><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">, an upcoming functional language in the </span><i style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">Lisp </i><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">tradition.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">You can check out the Lux repo over here: </span><span style="color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><a href="https://github.com/LuxLang/lux">https://github.com/LuxLang/lux</a></span></span><br />
<span style="color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">I am very pleased to announce that Lux 0.3.2 is ready, and in this release came in several cool features for the language, plus some additions to the standard library.</span></span><br />
<span style="color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif;">On this post, I'm going to talk about one such addition: concurrency, through the </span><span style="font-family: "courier new" , "courier" , monospace;">Async</span><span style="font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif;"> type.</span></span></span><br />
<span style="color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif;">But first, I need to talk about 2 other things which are going to be useful to understand: how to use monads in Lux, and the </span><span style="font-family: "courier new" , "courier" , monospace;">IO</span><span style="font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif;"> type.</span></span></span><br />
<h2>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">Monads</span></h2>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">I'm going to skip the details of what monads are and just assume that anyone reading this is already familiar with that abstraction.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">For those of you who don't know, I'll just say that </span><span style="color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><i>a monad is just a monoid in the category of endofunctors</i>.</span></span><br />
<span style="color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Easy-peasy.</span></span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">Anyway, the </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Monad</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> signature is defined in the </span><span style="background-color: white; color: #222222; font-size: 13.2px; line-height: 18.48px;"><span style="font-family: "courier new" , "courier" , monospace;">lux/control/monad</span></span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> module as this:</span><br />
<pre style="background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-family: "arial"; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (defsig #export (Monad m)
(: (Functor m)
_functor)
(: (All [a]
(-> a (m a)))
wrap)
(: (All [a]
(-> (m (m a)) (m a)))
join))
</code></pre>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">And, as you can see, it's defined as depending on the </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Functor</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> signature, which is defined in the </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">lux/control/functor</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> module as this:</span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<br />
<pre style="background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-family: "arial"; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (defsig #export (Functor f)
(: (All [a b]
(-> (-> a b) (f a) (f b)))
map))
</code></pre>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">Whereas Haskell has a return function for monads, Lux has renamed that to </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">wrap</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">Also, those of you who are already familiar with monads (perhaps from using Haskell) will notice that there is no mention of the bind (or >>=) function anywhere. The reason is that, for any monad, bind can just be implemented as the composition of the monad's </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">join</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> function, with its functor's </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">map</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> function, so bind was omitted from the definition.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">To make working with monads as easy as possible, Lux comes with it's own implementation of do-notation, through the </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">do</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> macro (located in </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">lux/control/monad</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">).</span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span><br />
<br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">For example:</span><br />
<pre style="background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-family: "arial"; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (def #export nat^
(Parser Int)
(do Parser/Monad
[n int^
_ (assert (i:>= n 0) "Expected a natural number (>= N 0)")]
(wrap n)))
</code></pre>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">This is a parser from the </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">lux/meta/syntax</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> module for writing macros. </span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">As you can see, the </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">do</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> macro in Lux requires that a monad implementation is explicitly passed to it.</span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">If you need to refer to the monad implementation while inside the </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">do</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> code, you can avoid having to type the full name and just refer to it as </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">%</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">, which is very useful for working with nested </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">do</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> expressions or for invoking monadic map (</span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">map%</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">) or any other function to which you need to pass the monad structure.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">Here's an example:</span><br />
<pre style="background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-family: "arial"; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (defsyntax #export (jvm-import [long-name? (tag?^ ["" "long"])]
[class-decl class-decl^]
[members (*^ (import-member-decl^ (second class-decl)))])
(do Lux/Monad
[kind (class-kind class-decl)
=members (map% % (member-import$ long-name? kind class-decl) members)]
(wrap (list& (class-import$ long-name? class-decl) (foldL list:++ list:unit =members)))))
</code></pre>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">In that example, the call to </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">map%</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> takes </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Lux/Monad</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> as just </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">%</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">, which is much easier to write.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">That macro, by the way, is one of the many macros for doing easy JVM interop in Lux; a topic we'll cover in a future post.</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span><br />
<h2>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">I/O</span></h2>
<br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">Now that you know how to use monads in Lux, it's time to talk about a really important one: the </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">IO</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> type (located in the </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">lux/codata/io</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> module).</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">Most languages have what could be described as informal I/O operations.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">That is, I/O operations that are not tracked by the compiler or regarded as anything special.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">One of the problems with this is that you cannot signal when a function has side effects or interacts with the real world.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">Another sad consequence is that you cannot easily separate side-effecting computations from pure ones, and this often leads to pervasive I/O being performed all over the program, which can lead to many kinds of subtle bugs.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">One that has probably bitten every Clojure programmer at some point is when you map some side-effecting function to some list and then wonder why nothing happens, only to later find out that you needed to apply dorun or doall to the list, as the laziness was interfering with the side-effects.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">Now... it might sound weird that Lux can have an </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">IO</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> type, considering the JVM does not offer any kind of separation between side-effecting code and pure code.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">The way Lux does it is by cheating, and defining the </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">IO</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> type in a very simple way:</span><br />
<pre style="background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-family: "arial"; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (deftype #export (IO a)
(-> Void a))
</code></pre>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">Yep. <i>Creatio ex nihilo</i>.</span><br />
<span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">IO</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> is a function from nothing to something.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">Very fitting, considering that you'll often get values from the outside world, and not through regular computation.</span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">How that works out is an implementation detail.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">Suffice it to say that it works pretty well, and it's often used for doing JVM interop, considering that many methods have side-effects and working with JVM objects should be faithfully modelled by the type-system.</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span><br />
<h2>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">Concurrency</span></h2>
<br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">The </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">IO</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> type is really useful, but it does have 1 problem: it works synchronously.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">Concurrency often requires communication between different threads or processes, and that communication is often done asynchronously.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">A lot of work has been done on designing a paradigm that can properly encode both the properties of concurrent execution, and the needs of programmers.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">While working on this release, I considered many options:</span><br />
<ul>
<li><span style="color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Futures & Promises</span></span></li>
<li><span style="color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Communicating Sequential Processes (CSP)</span></span></li>
<li><span style="color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Functional-Reactive Programming (FRP)</span></span></li>
<li><span style="color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">The Actor Model</span></span></li>
<li><span style="color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Software Transactional Memory (STM)</span></span></li>
</ul>
<br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">I eventually settled for what I considered the simplest and most primitive of all options (<i>Futures & Promises</i>), and then I simplified further.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">That was how I came up with the </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">(</span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Async a</span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">)</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> type (which is housed in the </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">lux/concurrency/async</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> module).</span><br />
<br />
. . .<br />
<br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">I'm not going to paste here the definition of </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Async</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">, since it's fairly complicated, as I had to defined a new class with (synchronized) methods to do all of the work.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">But suffice it to say that </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Async</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> is just a promise.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">The reason why I didn't name it Promise is that promises tend to be write-only, with futures providing the reading end.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Async</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> can be both written-to and read, with the detail that you can only write to an </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Async</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> once, and then it's value is set in stone.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">Every other write you attempt will fail, though rather than through an exception, it will just give back a </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">false</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> value, to signal failure.</span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">The beautiful thing about </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Async</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> is that it has a </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Monad</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> implementation, which means you can do computations with it and even compose </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Async</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> values.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">It's even possible to implement other paradigms on top of </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Async</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">, and the standard library already ships with a small module for doing Functional-Reactive Programming, located at </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">lux/concurrency/frp</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">FRP channels (</span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Chan</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">) are implemented in terms of </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Async</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">, which means FRP computations and regular async computations can interact seamlessly.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">CSP doesn't really offer much above </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Async</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">, which is why it wasn't implemented.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">The Actor Model offers a greater value proposition, but I felt that it was better to leave that for a full-fledged distributed-programming framework, which is why it wasn't added to the standard library.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">You might wonder whether it is possible to combine </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">IO</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> operations with </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Async</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">, and the answer to that is <b>yes</b> (but there is a caveat).</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">The road to </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Async</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> is a one-way street.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">You can always treat a synchronous operation asynchronously, but you can't do it the other way around, which is very important to note.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">That doesn't mean you cannot access the value of an </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Async</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> from synchronous code, but it does mean that the only resource you have available is polling for it's value until some thread sets it, as you cannot block on it synchronously.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;">The trick for turning an </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">IO</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> into an </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Async</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> is to use the </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">future</span><span style="background-color: white; color: #222222; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> function:</span><br />
<pre style="background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-family: "arial"; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (def #export (future computation)
(All [a] (-> (IO a) (Async a)))
...)
</code></pre>
<span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span><span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif; font-size: 13.2px; line-height: 18.48px;">The code will be run on a new thread and it's output will be stored in an </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Async</span><span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif; font-size: 13.2px; line-height: 18.48px;">, which you will receive.</span>
<span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span><span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif; font-size: 13.2px; line-height: 18.48px;">Finally, I gotta say that while working with </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Async</span><span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif; font-size: 13.2px; line-height: 18.48px;">, Lux will be using a thread pool in order to avoid an inordinate amount of threads to be spawned. It's size will correspond to the number of cores in your machine.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">future</span><span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif; font-size: 13.2px; line-height: 18.48px;">, however, does not use threads from this pool and always spawns a new one, to avoid the case of some </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">IO</span><span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> operation taking too long and blocking regular </span><span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px; line-height: 18.48px;">Async</span><span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif; font-size: 13.2px; line-height: 18.48px;"> operations by occupying a pooled-thread.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">_____________________________________________________________________________</span></span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">That's it for today, folks.</span></span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Hopefully you now understand how to use Lux for practical stuff involving both I/O and concurrency.</span></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span><span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif; font-size: 13.2px; line-height: 18.48px;">I'll be posting info on some more of the awesome things that came in v0.3.2 later on.</span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-size: 13.2px; line-height: 18.48px;"><span style="font-family: "arial" , "helvetica" , sans-serif;">Until then, take care and have fun (... and don't forget to check out the documentation for the <a href="https://github.com/LuxLang/lux/wiki/Standard-Library">Standard Library</a> on the repo, for more detailed info about the </span><span style="font-family: "courier new" , "courier" , monospace;">lux/concurrency/async</span><span style="font-family: "arial" , "helvetica" , sans-serif;"> and </span><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: "courier new" , "courier" , monospace;">lux/concurrency/frp</span><span style="font-family: "arial" , "helvetica" , sans-serif;"> modules</span></span><span style="font-family: "arial" , "helvetica" , sans-serif;">).</span></span><br />
<span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif; font-size: 13.2px; line-height: 18.48px;">See you next time :D</span><span style="background-color: white; color: #222222; font-family: "arial" , "helvetica" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
Eduardo Juliánhttp://www.blogger.com/profile/16436429020274670468noreply@blogger.com0tag:blogger.com,1999:blog-3344891259234150808.post-24752624455044215572015-12-24T22:29:00.001-08:002015-12-26T10:35:55.297-08:00Lux Tutorial #1: Simple TODO list using Vert.x<span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">Hello, and welcome to the 4th entry in the </span><b style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">Lux Devlog</b><span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">, a blog dedicated to the design and implementation of the </span><i style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">Lux Programming Language</i><span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">, an upcoming functional language in the </span><i style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">Lisp </i><span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">tradition.</span><br />
<span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">This post is going to be a very special one, because it's going to be the first full-fledged Lux tutorial.</span><br />
<span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">It's also going to be a special tutorial, because rather than just showing you some syntax, functions and features of Lux, I'm actually going to show you an actual <i>sample</i> program I made for this occasion in order to illustrate all the features I'll be introducing.</span><br />
<span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white;"><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">You can also get the source code of the program to play with it and study at your leisure from this repo: </span></span></span><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><a href="https://github.com/LuxLang/tutorial1">https://github.com/LuxLang/tutorial1</a></span></span><br />
<br />
<span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">OK, so... the 1st thing you need to do is clone that repo, as we're going to dive into the source code.</span><br />
<span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">But first things first. We need to know how to compile the program and it wouldn't be a bad idea to take a peek at the finished product before we start reading the code.</span><br />
<span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">First, make sure you have Leiningen installed, which is the build tool currently being used for Lux development.</span><br />
<span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">If you don't have Leiningen, you can find out how to install it over here: </span><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><a href="http://leiningen.org/">http://leiningen.org/</a></span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Got Leiningen? Great!</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Now, you need to get the Lux compiler we'll be using.</span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">Download this one from the 0.3.1 release: </span></span></span><span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 12px; line-height: 16.8px; text-align: justify;"><a href="https://github.com/LuxLang/lux/releases/download/0.3.1/luxc.jar">https://github.com/LuxLang/lux/releases/download/0.3.1/luxc.jar</a></span><span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> and place it in the </span><span style="font-family: Courier New, Courier, monospace;">tutorial1</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> directory.</span></span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">Next, fire up a terminal and head to the </span><span style="font-family: Courier New, Courier, monospace;">tutorial1</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> directory.</span></span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">Now, issue this command: </span></span></span><span style="color: #222222; font-family: Courier New, Courier, monospace;"><span style="font-size: 13.2px; line-height: 18.48px;">lein luxc compile</span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><br /></span></span></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Once the compilation process is complete, we can run the server.</span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">Type: </span><span style="font-family: Courier New, Courier, monospace;">java -jar target/jvm/program.jar</span></span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Now, go to <a href="http://localhost:8080/">http://localhost:8080/</a></span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Play with it all you want.</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">It's a very simple app.</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">As you can see, all of the work is being done in the server, with no JavaScript involved. That's because I wanted to focus the tutorial purely on Lux.</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><i>Note: There is no persistence for the TODO list, so once the server process is killed, your tasks are going to go away</i>.</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">By the way, the CSS was <i>borrowed</i> from the <a href="http://todomvc.com/">TodoMVC</a> project (with some minor alterations). All the credit for the beautiful design goes to them.</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Now, before we dig into the code, I think it's a good idea to delineate what we're going to see.</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">The app contains a small library for generating HTML from Lux (as Text), as well as a small library for generating CSS (also as Text).</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Aside from that, it includes some code for working with the <a href="http://vertx.io/">Vert.x</a> platform and some code for managing the state of the program (represented as a list, since it's a TODO program).</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Also, it would be a good idea to have some editor support when checking out the .lux files, so if you're an Emacs user, I suggest you install lux-mode. You can find it here: <a href="https://github.com/LuxLang/lux-mode">https://github.com/LuxLang/lux-mode</a></span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Now, without further ado, let's dive into the code!</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">_____________________________________________________________________________</span><br />
<span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<br />
<h2>
<span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: large;"><span style="line-height: 18.48px;">tutorial1/server/html</span></span></h2>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Before we get into the complicated stuff, let's get our feet wet with something simple... like HTML generation.</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Head over to this file and give it a glance.</span></span><br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (;import lux
(lux (data (text #open ("text:" Text/Monoid))
(list #refer #all #open ("" List/Functor List/Fold)))
(meta lux
syntax
(ast #as ast))))
</code></pre>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">The first thing you'll see is this.</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">The imports section is the first part in any Lux module (Lux modules are just files ending in the .lux extension).</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">You'll notice that, unlike in many other languages, the name of the module itself is never specified.</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">That reason is that, to avoid unnecessary repetition, Lux just assumes that the name of the file corresponds to the module itself. Also, the nesting of the directories corresponds to the nesting of modules.</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Now, let's analyse this for a moment.</span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">The first thing that's imported is the </span><span style="font-family: Courier New, Courier, monospace;">lux</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> module, which serves as a prelude full of useful functions and (mostly) macros.</span></span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span><span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">After that, I import the </span><span style="font-family: Courier New, Courier, monospace;">lux/data/text</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> and </span><span style="font-family: Courier New, Courier, monospace;">lux/data/list</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> modules, alongside </span><span style="font-family: Courier New, Courier, monospace;">lux/meta/lux</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">, </span></span></span><span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: 13.2px; line-height: 18.48px;">lux/meta/syntax</span><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;"> and </span><span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: 13.2px; line-height: 18.48px;">lux/meta/ast</span><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">.</span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">As you can image, nesting of module names can be done up to arbitrary depths.</span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">If you just import a module, as is the case for </span><span style="font-family: Courier New, Courier, monospace;">lux/meta/syntax</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">, you get all of it's exported definitions as top level definitions on your module.</span></span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">However, if you give the module extra options, that assumption is no longer made and you must explicitly </span><span style="font-family: Courier New, Courier, monospace;">#refer</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> which definitions you want. In the case of </span><span style="font-family: Courier New, Courier, monospace;">lux/data/list</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> I want everything, so I </span><span style="font-family: Courier New, Courier, monospace;">#refer #all</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">.</span></span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">I can also give aliases to modules, in cases in which I don't want to import what they have but would like to, instead, refer to every definition in a piecemeal manner, using the alias to avoid having to prefix every definition with the full module name.</span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">An example if this is when I import the </span><span style="font-family: Courier New, Courier, monospace;">lux/meta/ast</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> module. The alias is introduced with the </span><span style="font-family: Courier New, Courier, monospace;">#as</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> option.</span></span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">Finally, you'll see that there's a weird option called </span><span style="font-family: Courier New, Courier, monospace;">#open</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">. It's used for taking structures and generating top-level definitions out of their members. The text you see before each structure serves to declare a prefix to use when generating the top-level definitions. This is useful in order to avoid potential clashes, or just to better track what came from where.</span></span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">Thanks to those </span><span style="font-family: Courier New, Courier, monospace;">#open</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> options, we now have access to the </span><span style="font-family: Courier New, Courier, monospace;">map</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> and </span><span style="font-family: Courier New, Courier, monospace;">foldL</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> functions, both working for lists, but also to the </span><span style="font-family: Courier New, Courier, monospace;">text:++</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> function, for concatenating texts.</span></span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">There's a bit more to importing than what we've seen here, but we'll leave that for future lessons. For now, let's move on to the rest of this file.</span></span><br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (deftype #export Html Text)
(deftype #export Attributes
(List (, Text Text)))
</code></pre>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Here, we're defining what we mean by HTML and HTML attributes. As I previously said, our HTML will be Text, and our attributes will just be KV pairs of Text.</span></span><br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (def attributes^
(Parser (List (, Text AST)))
(record^ (*^ (&^ text^ id^))))
(defsyntax #export (@attrs [attrs attributes^])
(:: Lux/Monad (wrap (@list (` (: Attributes
(@list (~@ (map (: (-> (, Text AST) AST)
(lambda [[key val]]
(` [(~ (ast;text key)) (~ val)])))
attrs)))))))))
</code></pre>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Things start getting interesting, as we define our first macro!</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">To make defining HTML attributes a bit easier, we define the </span><span style="font-family: Courier New, Courier, monospace;">@attrs</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> macro to take the attributes in </span><span style="font-family: Courier New, Courier, monospace;">{ record syntax }</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> and generate the list of tuples we need for the action attributes.</span></span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">It even adds some code to do type-checking to ensure the result is a valid attributes object.</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">We can also see some pieces of Lux syntax you're probably unfamiliar with, so let's dissect this for a moment.</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">First, you'll notice I'm defining the macro using </span><span style="font-family: Courier New, Courier, monospace;">defsyntax</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">. There's a </span><span style="font-family: Courier New, Courier, monospace;">defmacro</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> macro for doing this too, but it's a bit more low-level and requires that you handle the AST tokens you receive manually.</span></span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">To make things easier, </span><span style="font-family: Courier New, Courier, monospace;">defsyntax</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> relies on monadic parsing of the AST tokens.</span></span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">Here, we're parsing the tokens using the </span><span style="font-family: Courier New, Courier, monospace;">attributes^</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> parser defined above and storing the result inside the </span><span style="font-family: Courier New, Courier, monospace;">attrs</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> variable.</span></span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">If you look at the definition of of </span><span style="font-family: Courier New, Courier, monospace;">attributes^</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">, you'll notice that it's build by using parser combinators. That's one of the beautiful things about monadic parsing, you can build bigger parsers by just combining smaller ones.</span></span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">Here, we're using the </span><span style="font-family: Courier New, Courier, monospace;">record^</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> combinator, which flattens the elements of records in order to provide the given parser with a list of the flattened KV pairs.</span></span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">The </span><span style="font-family: Courier New, Courier, monospace;">*^</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> combinator allows us to parse 0 or more instances of whatever the parser you give it can parse.</span></span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">Then, the </span><span style="font-family: Courier New, Courier, monospace;">&^</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> combinator receives two parsers and attempts to run them in sequence, returning a tuple of their outputs.</span></span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Courier New, Courier, monospace;">text^</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> only succeeds if it encounters a </span><span style="font-family: Courier New, Courier, monospace;">#TextS</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> token, in which case it returns it's content.</span></span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Courier New, Courier, monospace;">id^</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> is the identity parser and just returns to you the first </span><span style="font-family: Courier New, Courier, monospace;">AST</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> token it finds.</span></span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">The type of our </span><span style="font-family: Courier New, Courier, monospace;">attributes^</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> parser correctly represents the parser we build.</span></span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">Now, back to </span><span style="font-family: Courier New, Courier, monospace;">@attrs</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">!</span></span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">You'll notice there's some funny bit of syntax involving </span><span style="font-family: Courier New, Courier, monospace;">Lux/Monad</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> (which, by the way, is one of the definitions we imported from </span><span style="font-family: Courier New, Courier, monospace;">lux/meta/lux</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">). The </span><span style="font-family: Courier New, Courier, monospace;">::</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> macro allows us to use individual members from structures, and in this case we're using </span><span style="font-family: Courier New, Courier, monospace;">wrap</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> (Lux's version of Haskell's return function).</span></span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">We're wrapping a list of syntax tokens, with just 1 token being generated by the back-quote </span><span style="font-family: Courier New, Courier, monospace;">`</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> macro. We're generating our attributes KV list and each tuple is being generated by mapping a function over the attributes we parsed. The </span><span style="font-family: Courier New, Courier, monospace;">ast;text</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> function takes care of wrapping the text labels back as </span><span style="font-family: Courier New, Courier, monospace;">AST</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> nodes.</span></span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">We needed to parse them in the first place to ensure that they were really text nodes and not something silly, like numbers. But now it's time to turn them back into </span><span style="font-family: Courier New, Courier, monospace;">AST</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> nodes.</span></span></span><br />
<br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">. . .</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">Bellow </span><span style="font-family: Courier New, Courier, monospace;">@attrs</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> there are 2 funny-looking macro definitions, but I'll talk about them later, as they'll become necessary at the end of this file.</span></span></span><br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (def (concat-with sep elems)
(-> Text (List Text) Text)
(|> elems
(interpose sep)
(foldL text:++ "")))
(def (attrs->text attrs)
(-> Attributes Text)
(|> attrs
(map (lambda [[key val]] ($ text:++ key "=" "\"" val "\"")))
(concat-with " ")))
(def #export (node name attrs children)
(-> Text Attributes (List Html) Html)
($ text:++ "<" name " " (attrs->text attrs) ">" (concat-with " " children) "</" name ">"))
</code></pre>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">We're now at the meat of this, with the actual HTML generation.</span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">The </span><span style="font-family: Courier New, Courier, monospace;">node</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> function takes care of that, receiving the tag-name, it's attributes and any children the tag might have.</span></span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">The </span><span style="font-family: Courier New, Courier, monospace;">attrs->text</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> and </span><span style="font-family: Courier New, Courier, monospace;">concat-with</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> functions take care of the minutiae of how to generate some of the HTML code.</span></span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">However, it would be pretty tiresome to have to invoke the </span><span style="font-family: Courier New, Courier, monospace;">node</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> function every time we want to generate some HTML, and using the </span><span style="font-family: Courier New, Courier, monospace;">@attrs</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> macro would also become tiresome after a while.</span></span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">That's the reason behind the code right at the bottom of this file:</span></span><br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (do-template [<name>]
[(let% [<fun-name> (%tag-func-name% <name>)]
(def #export <fun-name>
(node (%tag% <name>)))
(defsyntax #export (<name> attrs [children (*^ id^)])
(let [attrs' (case attrs
[_ (#;RecordS _)]
(` (@attrs (~ attrs)))
_
attrs)]
(:: Lux/Monad (wrap (@list (` (<fun-name> (~ attrs') (@list (~@ children))))))))))]
[html]
## Head
[head]
[meta]
[link]
[title]
## Body
[body]
[div]
[span]
[a]
[form]
[input]
)
</code></pre>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">To make writing HTML in Lux easier, we're going to define some convenience macros for us.</span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">They're going to have the names of commonly used tags and when they receive the attributes, if they're in </span><span style="font-family: Courier New, Courier, monospace;">{ record syntax }</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">, the macro will simply wrap them inside an </span><span style="font-family: Courier New, Courier, monospace;">@attrs</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> call to ensure the proper conversion is performed.</span></span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">But wait, there's more!</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Knowing that sometimes we'll want to use regular functions instead of records for generating our HTML, we're also going to be generating functions that do the same thing as our macros.</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">This is also where I explain what's up with the </span><span style="font-family: Courier New, Courier, monospace;">%tag%</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> and </span><span style="font-family: Courier New, Courier, monospace;">%tag-func-name%</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> macros that were defined earlier.</span></span></span><br />
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">Since we're only providing the names of the macros to </span><span style="font-family: Courier New, Courier, monospace;">do-template</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">, we need some way to generate the tag from there (which has to be in text form), and also the name of the function.</span></span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222;"><span style="font-size: 13.2px; line-height: 18.48px;"><span style="font-family: Courier New, Courier, monospace;">%tag%</span><span style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"> turns a symbol into text, and thus takes care of the tag for use.</span></span></span><br />
<span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: 13.2px; line-height: 18.48px;">%tag-func-name%</span><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">, on the other hand, takes a symbol and appends a ' to the end, thereby turning </span><span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: 13.2px; line-height: 18.48px;">div</span><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;"> into </span><span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: 13.2px; line-height: 18.48px;">div'</span><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;"> and </span><span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: 13.2px; line-height: 18.48px;">span</span><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;"> into </span><span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: 13.2px; line-height: 18.48px;">span'</span><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">. These will be our functions.</span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">Also, I'd like to point out something that might have puzzled you.</span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">In the code for generating the macros for our tags, we receive the </span><span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: 13.2px; line-height: 18.48px;">attrs</span><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;"> </span><span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: 13.2px; line-height: 18.48px;">AST</span><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;"> node, but we don't specify how we parse it. It's just a symbol (</span><span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: 13.2px; line-height: 18.48px;">attrs</span><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">)!</span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">What's going on is that whenever </span><span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: 13.2px; line-height: 18.48px;">defsyntax</span><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;"> encounters just-a-symbol, it assumes you don't want to do any kind of fanciful parsing and just treats it as is you had written </span><span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: 13.2px; line-height: 18.48px;">[attrs id^]</span><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">.</span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">Also, you might be puzzled about the weird </span><span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: 13.2px; line-height: 18.48px;">let%</span><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;"> macro up there. If you've never seen it before, or you forgot how it worked, then I'd recommend you read this post before continuing: </span><span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><a href="http://luxlang.blogspot.com/2015/11/custom-pattern-matching-and-advanced.html">http://luxlang.blogspot.com/2015/11/custom-pattern-matching-and-advanced.html</a></span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">We've gone over our first Lux module! Now it's only 8 more to go!</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">Don't worry, though. Since we've seen a lot already, I won't be explain stuff we've already seen and I'll only talk about snippets introducing new concepts.</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;">With that in mind, let's proceed!</span></span><br />
<span style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"><span style="font-size: 13.2px; line-height: 18.48px;"><br /></span></span>
<br />
<h2>
<span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: large;"><span style="line-height: 18.48px;">tutorial1/server/css</span></span></h2>
<br />
The code is very similar to the one for HTML generation.<br />
CSS is also text and the style for each rule is also a text-based list of KVs, with the <span style="font-family: Courier New, Courier, monospace;">style^</span> parser and <span style="font-family: Courier New, Courier, monospace;">@style</span> macro being exact mirrors of <span style="font-family: Courier New, Courier, monospace;">attributes^</span> and <span style="font-family: Courier New, Courier, monospace;">@attrs</span> (which is not a coincidence, since I copy-pasted the code).<br />
<br />
The <span style="font-family: Courier New, Courier, monospace;">rule'</span> function is just like <span style="font-family: Courier New, Courier, monospace;">node</span> for HTML, and it even uses the same kinds of helpers.<br />
Since there isn't a variety of rules for CSS in the same way that there are a variety of tags, there was no need to generate several macros. <span style="font-family: Courier New, Courier, monospace;">rule</span> will do just fine.<br />
<br />
However, there is a major difference between <span style="font-family: Courier New, Courier, monospace;">rule</span> and <span style="font-family: Courier New, Courier, monospace;">node</span> which is that node gave you back 1 piece of text, whereas <span style="font-family: Courier New, Courier, monospace;">rule</span> gives you back a <span style="font-family: Courier New, Courier, monospace;">RuleSet</span>, which is a list of rules (which <i>are</i> text).<br />
The <span style="font-family: Courier New, Courier, monospace;">css</span> function takes care of joining them together into 1 piece of text (or CSS).<br />
<br />
The reason for <span style="font-family: Courier New, Courier, monospace;">rule</span> working the way it does is that is changes the <span style="font-family: Courier New, Courier, monospace;">ruleset</span> you give it in order to nest rules/styles.<br />
You'll see what I'm talking about once we generate some CSS later on.<br />
<br />
<h2>
<span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: large;"><span style="line-height: 18.48px;">tutorial1/server/core</span></span></h2>
<br />
Things start getting fun in this module.<br />
<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (;import lux
(lux (codata io)
(data maybe
(text #open ("text:" Text/Eq))
(list #refer #all #open ("" List/Functor))
(number #open ("i:" Int/Show)))
(host jvm)
(meta lux
(ast #as ast)
syntax))
(.. (html #as &html)
(css #as &css)))
</code></pre>
<br />
First, we notice something funny with our imports syntax.<br />
What's up with that <span style="font-family: Courier New, Courier, monospace;">..</span> over there? What does it do?<br />
As some of you might imagine, Lux's <span style="font-family: Courier New, Courier, monospace;">import</span> syntax supports some measure of relative positioning to about writing superfluous paths in our imports syntax.<br />
Both <span style="font-family: Courier New, Courier, monospace;">.</span> and <span style="font-family: Courier New, Courier, monospace;">..</span> are supported.<br />
Note, though, that Lux imports do not support the full syntax of file paths, as they're not file-paths, so trying something clever will probably just end up in a compiler error.<br />
With that said, relative positioning helps in writing shorter code, plus you also get the benefit that if you move modules around, you get to break less paths, as modules can be agnostic of what their parent modules happen to be.<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> ## [Host]
(jvm-import java.lang.String
(getBytes [] [] (Array byte)))
</code></pre>
<br />
Here we encounter our first instance of JVM interop.<br />
The <span style="font-family: Courier New, Courier, monospace;">jvm-import</span> macro generates types and functions for you, given descriptions of Java classes (or interfaces) and their methods.<br />
As you can see, the specs don't need to be complete and the classes can have type-parameters (which is not the case for String, though).<br />
<br />
Here, we're saying that the getBytes method doesn't have any type-parameters of it's own (the 1st tuple), nor does it take any arguments (the 2nd tuple). It returns an array of bytes.<br />
Mind you, Lux doesn't allow you to have variables or definitions of primitive JVM types, but arrays are fair game, as the JVM offers different kinds of arrays, optimized for each case.<br />
Whenever you're working with individual values inside those arrays, some measure of wrapping/unwrapping is performed, so buyer beware!<br />
<br />
In this case, <span style="font-family: Courier New, Courier, monospace;">jvm-import</span> will generate for us a <span style="font-family: Courier New, Courier, monospace;">String</span> definition, for the type, and a <span style="font-family: Courier New, Courier, monospace;">String::getBytes</span> definition, for a function masking the method call.<br />
For those of you who might be wondering, it's perfectly possible to do interop without this, but the Lux primitives for doing interop are cumbersome to use, since they map very directly to the JVM bytecode instructions. To avoid all that hassle, it's best to use macros such as <span style="font-family: Courier New, Courier, monospace;">jvm-import</span> (which, I forgot to say, comes from the <span style="font-family: Courier New, Courier, monospace;">lux/host/jvm</span> module).<br />
<br />
. . .<br />
<br />
Back the file!<br />
You'll be seeing various type definitions, as we define the basics for doing HTTP communications and request handling, separate from the primitives which Vert.x provides.<br />
We'll later be plugging things together in another module...<br />
<br />
The <span style="font-family: Courier New, Courier, monospace;">@headers</span> macro works just like <span style="font-family: Courier New, Courier, monospace;">@attrs</span> and <span style="font-family: Courier New, Courier, monospace;">@style</span>, since <span style="font-family: Courier New, Courier, monospace;">HttpHeaders</span> are also just lists of text KVs.<br />
<br />
We have some functions for easily generating HTTP responses and them some utility functions.<br />
Nothing too fancy here.<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (do-template [<name> <type> <content-type>]
[(def #export (<name> value)
(-> <type> HttpResponse)
(let [value-bytes (String::getBytes [] value)]
{#response-status 200
#response-headers (|> empty-headers
(add-header "Content-Length" (i:show (array-length value-bytes)))
(add-header "Content-Type" <content-type>))
#response-body value-bytes}))]
[html-response &html;Html "text/html"]
[css-response &css;CSS "text/css"]
)
</code></pre>
<br />
<span style="color: #222222;"><span style="font-family: inherit; line-height: 18.48px;">You'll notice, though, that we're using the </span><span style="font-family: Courier New, Courier, monospace; line-height: 18.48px;">String::getBytes</span><span style="font-family: inherit; line-height: 18.48px;"> function for the first time!</span></span><br />
<span style="color: #222222;"><span style="font-family: inherit; line-height: 18.48px;">The function takes the method arguments as a tuple (in this case empty, since there are none), and the object is being given last.</span></span><br />
<span style="color: #222222;"><span style="font-family: inherit; line-height: 18.48px;"><br /></span></span>
<span style="color: #222222;"><span style="font-family: inherit; line-height: 18.48px;">You'll also notice the </span><span style="font-family: Courier New, Courier, monospace; line-height: 18.48px;">array-length</span><span style="font-family: inherit; line-height: 18.48px;"> macro being used. It's also defined inside the </span><span style="font-family: Courier New, Courier, monospace; line-height: 18.48px;">lux/host/jvm</span><span style="font-family: inherit; line-height: 18.48px;"> module.</span></span><br />
<h2>
<span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: large;"><span style="line-height: 18.48px;">tutorial1/server/host</span></span></h2>
<br />
It's time to drop the kiddy gloves and get into full-on interop territory!<br />
Let's take a look at some of the new things this module has got to show us!<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (jvm-import io.vertx.core.Vertx
(#static vertx [] [] io.vertx.core.Vertx #io)
(createHttpServer [] [] io.vertx.core.http.HttpServer #io)
(deployVerticle [] [io.vertx.core.Verticle] void #io))
</code></pre>
<br />
Here, you'll notice there's an odd <span style="font-family: Courier New, Courier, monospace;">#io</span> tag at the end of our methods.<br />
This is one of the nice services <span style="font-family: Courier New, Courier, monospace;">jvm-import</span> can provide for us.<br />
With this, it wraps the type of the return value inside an <span style="font-family: Courier New, Courier, monospace;">IO</span> type, so we can better state that we're dealing with a side-effecting or stateful methods.<br />
<br />
We can also see that by using <span style="font-family: Courier New, Courier, monospace;">#static</span>, we can import static methods into our code.<br />
Unlike normal methods, static methods don't take object instances are arguments, so it's fine to just pass them the arguments tuple.<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (jvm-import io.vertx.core.http.HttpServerResponse
(headers [] [] io.vertx.core.MultiMap)
(setStatusCode [] [int] io.vertx.core.http.HttpServerResponse)
(write [] [io.vertx.core.buffer.Buffer] io.vertx.core.http.HttpServerResponse)
(end [] [] void))
</code></pre>
<br />
Methods with void return values just give you back <span style="font-family: Courier New, Courier, monospace;">[]</span> (unit) as the return value.<br />
<br />
<pre style="background: rgb(240, 240, 240); border: 1px dashed rgb(204, 204, 204); font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; width: 646.469px;"><code style="word-wrap: normal;"> (jvm-import #long (java.util.List e)
(size [] [] int)
(get [] [int] e))
</code></pre>
<br />
If, for whatever reason, we don't want the name of an imported class to get short when importing it, we can just use the <span style="font-family: Courier New, Courier, monospace;">#long</span> option to specify that we want it's long name.<br />
In this case, using it's short name would make it clash with Lux's <span style="font-family: Courier New, Courier, monospace;">List</span> type, so we'd rather avoid that.<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (def (extract-param entries idx)
(-> (java.util.List (Map$Entry Text Text)) Int (, Text Text))
(let [entry (java.util.List::get [(_jvm_l2i idx)] entries)]
[(Map$Entry::getKey [] entry) (Map$Entry::getValue [] entry)]))
</code></pre>
<br />
Sometimes, we need to perform some conversions when doing JVM interop.<br />
Lux's <span style="font-family: Courier New, Courier, monospace;">Int</span> type actually maps to Java's longs, rather than ints. In order to invoke java.util.List's get method, we need to turn our long into an int, and that's the job of the <span style="font-family: Courier New, Courier, monospace;">_jvm_l2i</span> special form.<br />
There are many others like it for performing simple conversions between primitives.<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (do-template [<name> <method> <type>]
[(def (<name> req)
(-> HttpServerRequest <type>)
(let [entries (|> req (<method> []) (MultiMap::entries []))]
(map (extract-param entries)
(range Int/Enum 0 (dec (_jvm_i2l (java.util.List::size [] entries)))))))]
[get-headers HttpServerRequest::headers &;HttpHeaders]
[get-query-params HttpServerRequest::params &;HttpParams]
[get-form-params HttpServerRequest::formAttributes &;HttpParams]
)
</code></pre>
<br />
If you haven't gotten acquainted to it yet, <span style="font-family: Courier New, Courier, monospace;">|></span> is Lux's pipeline macro, and it works the same as Clojure's ->> macro.<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (def (respond! response request)
(-> &;HttpResponse HttpServerRequest (IO (,)))
(do IO/Monad
[#let [(\slots [#&;response-status #&;response-headers #&;response-body]) response]
$response (HttpServerRequest::response [] request)
#let [_ (HttpServerResponse::setStatusCode [(_jvm_l2i response-status)] $response)
mm (foldL (: (-> MultiMap (, Text Text) MultiMap)
(lambda [headers pair] (MultiMap::add pair headers)))
(HttpServerResponse::headers [] $response)
response-headers)
_ (HttpServerResponse::write [(Buffer::buffer [response-body])] $response)
_ (HttpServerResponse::end [] $response)]]
(wrap [])))
</code></pre>
<br />
Here, we're getting our first look into how to write monadic code in Lux.<br />
<span style="font-family: Courier New, Courier, monospace;">do</span> is our macro for monadic do-notation (implemented inside the <span style="font-family: Courier New, Courier, monospace;">lux/control/monad</span> module).<br />
You give it the monad implementation you need and it does it's thing.<br />
<span style="font-family: Courier New, Courier, monospace;">#let</span> is an option for making simple lexical binding and <span style="font-family: Courier New, Courier, monospace;">\slots</span> helps us easily destructure the response in order to translate it into something Vert.x can understand.<br />
<br />
Since we passed the <span style="font-family: Courier New, Courier, monospace;">#io</span> option when importing <span style="font-family: Courier New, Courier, monospace;">HttpServerRequest::response</span>, it plays well with the <span style="font-family: Courier New, Courier, monospace;">IO/Monad</span>.<br />
The methods in HttpServerResponse weren't annotated with <span style="font-family: Courier New, Courier, monospace;">#io</span> because I forgot (<i>hehe</i>), but if they had been, they would have also been used directly in the do-notation.<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (def (request$ req body)
(-> HttpServerRequest &;HttpBody &;HttpRequest)
{#&;request-method (|> req (HttpServerRequest::method []) (Object::toString []) &;HttpMethod$ (? #&;OPTIONS))
#&;request-uri (let [raw-uri (HttpServerRequest::uri [] req)]
(? raw-uri
(do Maybe/Monad
[[uri params] (text;split-with "?" raw-uri)]
(wrap uri))))
#&;request-headers (get-headers req)
#&;request-params (get-params req)
#&;request-body body})
</code></pre>
<br />
You might be wondering what's the deal with the <span style="font-family: Courier New, Courier, monospace;">?</span> thingy over there.<br />
That's just a function from the <span style="font-family: Courier New, Courier, monospace;">lux/data/maybe</span> module which does the same thing as Scala's getOrElse method for Option.<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (def (http-handler server)
(-> &;RequestHandler (Handler HttpServerRequest))
(object java.lang.Object [(io.vertx.core.Handler io.vertx.core.http.HttpServerRequest)]
[]
(#override (io.vertx.core.Handler A) handle [] [(vreq A)] void
(exec (|> vreq
(HttpServerRequest::setExpectMultipart [true])
(HttpServerRequest::bodyHandler
[(body-handler (lambda [body']
(let [body (Buffer::getBytes [] body')]
(do IO/Monad
[#let [request (request$ vreq body)]
response (server request)]
(respond! response vreq)
))))]))
[]))))
</code></pre>
<br />
Whoah! What is going on over here!?<br />
<br />
In order to handle requests and perform other operations, we must give Handler implementations to Vert.x, so we better start generating some JVM classes!<br />
<br />
The <span style="font-family: Courier New, Courier, monospace;">object</span> macro helps use generate anonymous classes. Think of it as a mirror of Clojure's proxy macro.<br />
We specify the super class and any interfaces involved. Any of the super-types can be parameterized, as we see in the case of Handler.<br />
The final tuple is for constructor arguments to pass to the super class, but in most cases it's going to be empty.<br />
<br />
You can only override inherited methods and can't create new ones inside anonymous class definitions, which is why there's that <span style="font-family: Courier New, Courier, monospace;">#override</span> tag over there.<br />
When we override a method, we must specify who it belongs to.<br />
In this case, it's Handler's. We're also specifying that we'll be referring to Handler's type-parameter as <span style="font-family: Courier New, Courier, monospace;">A</span>.<br />
Then comes the name of the method, then a tuple with any method-local type-parameters, then a tuple with any arguments to the method (in this case <span style="font-family: Courier New, Courier, monospace;">vreq</span>, of type <span style="font-family: Courier New, Courier, monospace;">A</span>), and then comes the return type of the method (remember that void stands for <span style="font-family: Courier New, Courier, monospace;">[]</span>/unit).<br />
<br />
Don't worry about <span style="font-family: Courier New, Courier, monospace;">vreq</span> being of type <span style="font-family: Courier New, Courier, monospace;">A</span>. The compiler matches that to <span style="font-family: inherit;">HttpServerRequest</span>, as per the super-interface previously specified.<br />
<br />
Finally, the <span style="font-family: Courier New, Courier, monospace;">exec</span> macro allows us to execute several expressions and only gives back the value of the final expression, which makes it a great macro for writing side-effecting imperative code.<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (def (verticle$ port server-fun vertx)
(-> &;Port &;RequestHandler Vertx Verticle)
(object io.vertx.core.AbstractVerticle []
[]
(#override io.vertx.core.AbstractVerticle start [] [(start io.vertx.core.Future)] void
(exec (run-io (do IO/Monad
[http-server (Vertx::createHttpServer [] vertx)
_ (HttpServer::requestHandler [(http-handler server-fun)] http-server)]
(HttpServer::listen [(_jvm_l2i port)] http-server)))
[]))
(#override io.vertx.core.AbstractVerticle stop [] [(stop io.vertx.core.Future)] void #throws [java.lang.Exception]
(run-io (print-line "Verticle stopped!")))))
</code></pre>
<br />
Here, we see that you can also specify any exceptions the method might <span style="font-family: Courier New, Courier, monospace;">#throw</span>, and we also encounter the <span style="font-family: Courier New, Courier, monospace;">run-io</span> function, for executing <span style="font-family: Courier New, Courier, monospace;">IO</span> actions.<br />
<br />
<h2>
<span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: large;"><span style="line-height: 18.48px;">tutorial1/core</span></span></h2>
<br />
This module only has a tiny type definition for the tasks in our TODO list.<br />
<br />
<h2>
<span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: large;"><span style="line-height: 18.48px;">tutorial1/state</span></span></h2>
<br />
This module is a bit more interesting.<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (jvm-import (java.util.concurrent.CopyOnWriteArrayList e)
(<init> [] []))
## [Types]
(deftype #export AppState
(CopyOnWriteArrayList &;Task))
(deftype #export AppData
(List (, Int &;Task)))
</code></pre>
<br />
We use <span style="font-family: Courier New, Courier, monospace;">CopyOnWriteArrayList</span> for storing our task list.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">AppData</span> pairs our tasks with ints (their indices within the list) in order to be able to refer to them later on when marking tasks as completed or deleting them.<br />
<br />
The rest of the file just contains bookkeeping functions for handling the program's state.<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (def #export (clear-completed state)
(-> AppState (IO Bool))
(do IO/Monad
[task-list (get-task-list state)
_ (|> task-list
reverse
(map% % (: (-> (, Int &;Task) (IO Bool))
(lambda [[idx task]]
(if (completed-task? task)
(delete-task idx state)
(wrap true))))))]
(wrap true)))
</code></pre>
<br />
This last function is a bit weirder because of all the % in it.<br />
<span style="font-family: Courier New, Courier, monospace;">map%</span> is for mapping functions that return monadic values over lists. Think of it as a Lux mirror of Haskell's mapM function.<br />
The loose <span style="font-family: Courier New, Courier, monospace;">%</span> next to is is a bit more puzzling though... What is it!?<br />
It's actually just a simple lexical binding made by the <span style="font-family: Courier New, Courier, monospace;">do</span> macro. It contains the monad being used.<br />
It's made so it's possible to refer to <span style="font-family: Courier New, Courier, monospace;">IO/Monad</span> (or whatever monad is being used) anywhere inside the code without having to type the full name each time.<br />
Pretty convenient!<br />
<br />
<h2>
<span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: large;"><span style="line-height: 18.48px;">tutorial1/util</span></span></h2>
<br />
This module just contains a bunch of paths and other small values that are used in other parts of the codebase.<br />
<br />
<h2>
<span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: large;"><span style="line-height: 18.48px;">tutorial1/ui</span></span></h2>
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> ## [Types]
(deftype #export DisplayFilter
(| #All
#Active
#Completed))
## [Structs]
(defstruct DisplayFilter/Eq (Eq DisplayFilter)
(def (= x y)
(case [x y]
(\template [<tag>]
[[<tag> <tag>] true])
([#All] [#Active] [#Completed])
_
false)))
</code></pre>
<br />
If you played with the app on your browser prior to reading the rest of the tutorial, you'll have noticed that you can filter the tasks that you see on screen.<br />
<br />
This type helps with that, and we later use it's <span style="font-family: Courier New, Courier, monospace;">Eq</span> structure to help figure out which filter the user chose.<br />
<br />
. . .<br />
<br />
I won't put here the full definition of <span style="font-family: Courier New, Courier, monospace;">css</span> because it's too large.<br />
It's like that for a reason. I chose not to refactor it to make something a bit easier to spot and grasp.<br />
<br />
Remember that back when discussing CSS generation I said you could nest rules to establish a styling hierarchy?<br />
Well, here you can see how that plays out.<br />
In the CSS being generated, the selectors nest, so you can end up having something like <span style="font-family: Courier New, Courier, monospace;">.todo > .header > .new-task-form > .new-task-input</span><br />
Nice, huh?<br />
Of course, in real code I'd have just refactored every part and separated them, but having them all lumped together helps in better understanding how each style interacts with the rest.<br />
<br />
. . .<br />
<br />
After that, we get a bunch of functions for generating HTML, using the macros we defined previously in our little HTML DSL module.<br />
Feel free to peruse all you want.<br />
<br />
<h2>
<span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: large;"><span style="line-height: 18.48px;">tutorial1</span></span></h2>
<br />
Alright!<br />
This is it!<br />
It's time to face the final boss!<br />
<br />
The <span style="font-family: Courier New, Courier, monospace;">handler</span> function (which is also too large to paste here!) contains the logic for dispatching the HTTP requests and figuring out what to do.<br />
<br />
Since there are currently no web-frameworks for Lux, I don't have something like Clojure's Ring or Compojure to simplify routing for me, so I just do a very simple manual dispatching of the incoming requests.<br />
<br />
There's nothing in this function that hasn't been seen yet (except, perhaps, the <span style="font-family: Courier New, Courier, monospace;">\~</span> macro, but you can read more about it here: <a href="http://luxlang.blogspot.com/2015/11/custom-pattern-matching-and-advanced.html">http://luxlang.blogspot.com/2015/11/custom-pattern-matching-and-advanced.html</a>)<br />
I'll just leave you two alone for a moment...<br />
<br />
Back here so soon?<br />
OK, then let's discuss the final piece of the puzzle:<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (program args
(do IO/Monad
[app-state &&state;gen-state]
(&&server-host;deploy-server &&util;server-port (handler app-state))))
</code></pre>
<br />
<span style="font-family: Courier New, Courier, monospace;">program</span> is to Lux programs as main is to programs in other languages.<br />
You get a list of strings as your sole input and you must provide an <span style="font-family: Courier New, Courier, monospace;">(IO Unit)</span> value as the result.<br />
Here, we're just initializing the program's state to a fresh list and deploying our server with a <span style="font-family: Courier New, Courier, monospace;">handler</span> bound to our state.<br />
<br />
<h2>
<span style="color: #222222; font-family: Courier New, Courier, monospace; font-size: large;"><span style="line-height: 18.48px;">project.clj</span></span></h2>
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (defproject lux/tutorial1 "0.1.0-SNAPSHOT"
:plugins [[lux/lein "0.1.0"]]
:dependencies [[lux/stdlib "0.3.1"]
[io.vertx/vertx-web "3.0.0"]]
:lux/program "tutorial1")
</code></pre>
<br />
I cannot end this tutorial without first discussing the glue that allows the Leiningen build tool to compile Lux programs.<br />
<br />
The lux/lein plugin makes use of the luxc.jar file you downloaded previously to compile this tutorial.<br />
In the dependencies, we ask for both the Lux standard library and for Vert.x.<br />
<br />
We must also specify the name of the module containing the <span style="font-family: Courier New, Courier, monospace;">program</span> statement.<br />
<br />
<span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; line-height: 18.48px;">_____________________________________________________________________________</span><br />
<br />
This was a long read, but hopefully it was worth your while.<br />
I'm very happy to finally be able to share this tutorial with you and I hope it has helped you understand how to use Lux to build real programs of your own design.<br />
<br />
There will be more tutorials in the future (hopefully much shorter than this one), so stay tuned.<br />
<br />
And if you have any questions, feel free to post your comments down below.<br />
I'll gladly help in any way I can.Eduardo Juliánhttp://www.blogger.com/profile/16436429020274670468noreply@blogger.com11tag:blogger.com,1999:blog-3344891259234150808.post-17716775837081619412015-11-12T07:51:00.001-08:002015-11-12T07:51:28.998-08:00Custom pattern-matching and advanced macrologyHello, and welcome to the 3rd entry in the <b>Lux Devlog</b>, a blog dedicated to the design and implementation of the <i>Lux Programming Language</i>, an upcoming functional language in the <i>Lisp</i> tradition.<br />
<br />
Today, I'll talk about 2 really interesting subjects that go hand in hand and that give Lux a lot of its power and expressiveness.<br />
<br />
<h3>
First: Custom pattern-matching</h3>
<br />
Before explaining the details, I'll talk a bit about the genesis of this feature...<br />
<br />
Back in the early days of Lux's design & development, I was thinking about syntax for lists.<br />
Some languages (such as Haskell and JavaScript) offer custom syntax for list or array data-structures since the regular syntax for building data-structures tends to be a bit cumbersome to use, while lists are very commonly used data-structures.<br />
<br />
Just consider the difference between writings this:<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> [1, 2, 3, 4]
</code></pre>
versus writing this:<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> Cons 1 (Cons 2 (Cons 3 (Cons 4 Nil)))
</code></pre>
<br />
While designing Lux, I came to the conclusion that adding custom syntax for lists was, in a way, betraying the language. Rather than come up with a quick-and-dirty fix to the problem of lists, I wanted to have consistent and general ways to deal with data-structures, while also having comfortable syntax for lists. In short, <i>I wanted to have my cake and eat it too</i>.<br />
<br />
The solution for building lists was pretty easy. In a language with macros, the easiest way to fix these kinds of syntax issues was to write a macro... and that's exactly what I did:<br />
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (@list 1 2 3 4) ## This might surprise some of you, as an earlier version didn't have the @ sign...
</code></pre>
<br />
There is also an alternative version, which takes a "<i>tail</i>" as it's last argument<br />
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (@list& 1 2 3 4 (@list 5 6 7 8))
</code></pre>
<br />
OK, so that takes care of building lists, but there is still something missing...<br />
There's no point in building data-structures if you can't tear them apart later on. The mechanism for that is pattern-matching. And here is where we encounter our problem...<br />
<br />
Macros work well in regular code, but pattern-matching is special. Patterns are not expressions. You're not supposed to evaluate a pattern in order to get something out of it.<br />
However, the syntax for writing patterns turns out to be identical to the syntax for writing (certain kinds of) expressions.<br />
<br />
The answer to this question might seem obvious to a lot of you... and it's also obvious to me (<i>in hindsight</i>). But to a prior version of me, many months ago, it wasn't such an obvious thing. I struggled with an answer for weeks and even considered just having custom syntax for lists and give up on the subject...<br />
<br />
And then I had my "<i>aha!</i>" moment. If macros give me the syntax to build lists, and that syntax is the same I need for patterns, then why not just generate patterns with macros too. Sounds obvious, right? (<i>In hindsight...</i>)<br />
<br />
But there was still the matter of how do I implement it.<br />
Do I traverse the patterns to check for all macros that show up and expand those?<br />
That seems easy, but then I thought of something...<br />
<br />
Macros are pretty flexible tools. Building code for making data-structures is just one of the myriad things you can achieve.<br />
But what if my patterns could care about more than just destructuring things.<br />
I can't just expand macros in place whenever I see them, because I'd be assuming every macro is there to generate destructuring code for me.<br />
I need to add more control, and include macros that allow me to do more than just easily decompose data-structures.<br />
<br />
And so, the idea for <i>custom pattern-matching</i> was born.<br />
<br />
The concept is pretty simple, the pattern-matching macro (<span style="font-family: "courier new" , "courier" , monospace;">case</span>) checks patterns to see if there is a top-level macro invocation. If so, that macro gets involved with both the pattern <i><b>and</b></i> the body that is to be executed for that pattern. Whatever comes out of the macro gets substituted for the pattern and the body, and the macro-expansion process is repeated until no more macros are left.<br />
<br />
The beautiful thing is that, since the body is also included in the macro call, you can have pattern-matching macros that transform their bodies or that repeat them an arbitrary amount of times. The power unleashed is very impressive, and I have only scratched the surface of what can be achieved.<br />
<br />
Now, without further ado, it's time for some demonstrations :D<br />
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (def (to-pairs xs)
(All [a] (-> (List a) (List (, a a))))
(case xs
(\ (@list& x1 x2 xs'))
(@list& [x1 x2] (to-pairs xs'))
_
#;Nil))
</code></pre>
<br />
The <span style="font-family: "courier new" , "courier" , monospace;">\</span> macro has the simple task of expanding every macro it finds inside the pattern. It's the simplest of the pattern-matching macros and its use is very common (specially when working with lists).<br />
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (deftype Weekday
(| #Sunday
#Monday
#Tuesday
#Wednesday
#Thursday
#Friday
#Saturday))
(def (weekend? day)
(-> Weekday Bool)
(case day
(\or #Sunday #Saturday)
true
_
false))
</code></pre>
<br />
The <span style="font-family: "courier new" , "courier" , monospace;">\or</span> macro repeats the body given to it for every pattern you give it. That way, you can reuse the body whenever you have patterns that involve returning the same result.<br />
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> ## This is an actual structure from the lux/meta/ast file:
(defstruct #export AST/Eq (Eq AST)
(def (= x y)
(case [x y]
(\template [<tag> <struct>]
[[[_ (<tag> x')] [_ (<tag> y')]]
(:: <struct> (= x' y'))])
([#;BoolS Bool/Eq]
[#;IntS Int/Eq]
[#;RealS Real/Eq]
[#;CharS Char/Eq]
[#;TextS Text/Eq]
[#;SymbolS Ident/Eq]
[#;TagS Ident/Eq])
(\template [<tag>]
[[[_ (<tag> xs')] [_ (<tag> ys')]]
(and (:: Int/Eq (= (size xs') (size ys')))
(foldL (lambda [old [x' y']]
(and old (= x' y')))
true
(zip2 xs' ys')))])
([#;FormS]
[#;TupleS])
[[_ (#;RecordS xs')] [_ (#;RecordS ys')]]
(and (:: Int/Eq (= (size xs') (size ys')))
(foldL (lambda [old [[xl' xr'] [yl' yr']]]
(and old (= xl' yl') (= xr' yr')))
true
(zip2 xs' ys')))
_
false)))
</code></pre>
<br />
<span style="font-family: "courier new" , "courier" , monospace;">\template</span> is the pattern-matching sibling to the do-template macro. It allows you to reuse the code of the body, with some minor modifications to make it more suitable to each particular case.<br />
After the <span style="font-family: "courier new" , "courier" , monospace;">\</span> macro, this is probably the most handy pattern-matching macro to have around.<br />
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> ## Please forgive the super-contrived example
(deftype MyRecord
(& #foo Int
#bar Int
#baz Text))
(def (sum rec)
(-> MyRecord Int)
(case rec
(\slots [#foo #bar])
(i:+ foo bar)))
</code></pre>
<br />
<span style="font-family: "courier new" , "courier" , monospace;">\slots</span> is Lux's counterpart to Clojure's <span style="font-family: "courier new" , "courier" , monospace;">:keys</span> destructuring syntax.<br />
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> ## Again, sorry for the contrived example...
(def type-1 "foo")
(def type-2 "bar")
(def type-3 "baz")
(def (process-message message)
(-> (, Text Data) (,))
(case message
(\~ [(~ type-1) data]) (do-something data)
(\~ [(~ type-2) data]) (do-something-else data)
(\~ [(~ type-3) data]) (do-another-thing data)))
</code></pre>
<br />
Have you ever wanted to reuse a literal value in a situation that doesn't allow you the use of variables?<br />
That's a bit problematic, as you end up repeating the same literal value over and over again, introducing the risk of bugs, should the value every change.<br />
<br />
The <span style="font-family: "courier new" , "courier" , monospace;">\~</span> macro is there for precisely this purpose. Just tell it what you need inlined and let it work it's magic.<br />
<b><i>Note: It only works with Bool, Int, Real, Char and Text</i></b><br />
<br />
Finally, I've got a nice treat for you guys...<br />
<br />
Lux favors eager evaluation over lazy evaluation. However, we all know that some times laziness can be useful, and there are even some data-structures that depend on it, such as streams.<br />
<br />
Lux offers a type for doing lazy evaluation:<br />
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (deftype #export (Lazy a)
(All [b]
(-> (-> a b) b)))
</code></pre>
<br />
In Lux, <span style="font-family: "courier new" , "courier" , monospace;">Lazy</span> is just like the <span style="font-family: "courier new" , "courier" , monospace;">Cont</span> type in Haskell, except that it's arguments are in the reverse order.<br />
Streams are defined in terms of <span style="font-family: "courier new" , "courier" , monospace;">Lazy</span>:<br />
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (deftype #export (Stream a)
(Lazy (, a (Stream a))))
</code></pre>
<br />
This means that streams are actually functions.<br />
<br />
Now... some of you might think "<i>if streams are functions, that means I can't pattern-match against them</i>".<br />
Well, my friend, you're wrong!<br />
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (def (take-s n xs)
(All [a] (-> Int (Stream a) (List a)))
(if (i:<= n 0)
#;Nil
(case stream
(\stream& x xs')
(#;Cons x (take-s (dec n) xs')))))
</code></pre>
<br />
The <span style="font-family: "courier new" , "courier" , monospace;">\stream&</span> macro modifies the body so that pattern-matching on streams amounts to running the functions appropriately to extract the values.<br />
Thanks to pattern-matching macros, we can actually pattern-match against functions ^_^ .<br />
<br />
BTW, I have talked about what macros come by default in the Lux standard library, but I haven't shown how they're implemented.<br />
Just so you can get an idea, here's the implementation for the <span style="font-family: "courier new" , "courier" , monospace;">\</span> macro:<br />
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (defmacro' #export (\ tokens)
(case tokens
(#Cons body (#Cons pattern #Nil))
(do Lux/Monad
[pattern+ (macro-expand-all pattern)]
(case pattern+
(#Cons pattern' #Nil)
(wrap (@list pattern' body))
_
(fail "\\ can only expand to 1 pattern.")))
_
(fail "Wrong syntax for \\")))
</code></pre>
<br />
Also, I haven't mentioned something very important.<br />
Even though those macros can only work thanks to the <span style="font-family: Courier New, Courier, monospace;">case</span> macro macro-expanding the patterns, there are other macros out there which use <span style="font-family: "courier new" , "courier" , monospace;">case</span> in their implementations, and they can also benefit from pattern-matching macros.<br />
<br />
Some of those macros are the <span style="font-family: "courier new" , "courier" , monospace;">let</span> macro, the <span style="font-family: "courier new" , "courier" , monospace;">lambda</span> macro, and the <span style="font-family: "courier new" , "courier" , monospace;">do</span> macro.<br />
<i>That's right</i>, you can use custom pattern-matching against the arguments to your functions, or inside your <i>do-notation</i>, or even in good ol' <span style="font-family: "courier new" , "courier" , monospace;">let</span> forms. <i><b>How cool is that!?</b></i><br />
<br />
_____________________________________________________________________________<br />
<br />
<h3>
Second: Inter-operating macros</h3>
<br />
I know I've talked a lot already, but there's one other topic I want to discuss on this post, and that is how to get macros to inter-operate.<br />
<br />
As the custom pattern-matching examples show, you can unlock great power when your macros can work together, rather than separately, and Lux already reaps some of that power outside of the boundaries of pattern-matching.<br />
<br />
To get macros to play together, you need to do 2 things:<br />
<br />
<ol>
<li>Some macros must perform macro-expansions on the arguments they receive, in order to process the outputs</li>
<li>There must be some kind of "<i>contract</i>" between the outer macro and the inner macros</li>
</ol>
<br />
The first part is pretty obvious. If not because <span style="font-family: "courier new" , "courier" , monospace;">case</span> does macro-expansion on the patterns it receives, none of the magic would happen.<br />
<br />
But the second part is often missed by macro writers in other lisps. Without a common contract, communication becomes impossible and there can be no cooperation.<br />
<br />
<h4>
What's a common contract?</h4>
<br />
Consider this: whatever your pattern-matching macros generate, some rules must always stand:<br />
<br />
<ol>
<li>They must have an even number of outputs (since you're substituting both the pattern <i><b>and</b></i> the body).</li>
<li>For the patterns being generated, they must either be primitive forms suitable for regular pattern-matching, or they must be macro calls to be further expanded.</li>
</ol>
<br />
If any of these 2 rules is broken, the <span style="font-family: "courier new" , "courier" , monospace;">case</span> macro is going to complain about it.<br />
<br />
However, this isn't the only common contract macros can have and Lux already has a few macros with their own contracts.<br />
<br />
<h4>
The <span style="font-family: "courier new" , "courier" , monospace;">defsig</span> common contract</h4>
<br />
You might remember the <span style="font-family: "courier new" , "courier" , monospace;">defsig</span> macro from the last blog post (if not, I advise you to <a href="http://luxlang.blogspot.com/2015/11/luxs-values-types-signatures-structures.html">go read it</a>).<br />
What you might not know is that you can actually use other macros inside it's body.<br />
<br />
Here's a nice example (from the <span style="font-family: "courier new" , "courier" , monospace;">lux/control/number</span> module):<br />
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (defsig #export (Number n)
(do-template [<name>]
[(: (-> n n n) <name>)]
[+] [-] [*] [/] [%])
(do-template [<name>]
[(: (-> n n) <name>)]
[negate] [signum] [abs])
(: (-> Int n)
from-int)
)
</code></pre>
<br />
The <span style="font-family: "courier new" , "courier" , monospace;">Number</span> signature provides simple math operations.<br />
There are already implementations for <span style="font-family: "courier new" , "courier" , monospace;">Int</span> and <span style="font-family: "courier new" , "courier" , monospace;">Real</span> in the standard library.<br />
And, as you can see, I make liberal use of the <span style="font-family: "courier new" , "courier" , monospace;">do-template</span> macro to reduce boiler-plate.<br />
<br />
The reason why this works is simple: every member of the signature must take the form:<br />
<span style="font-family: "courier new" , "courier" , monospace;">(: <type> <name>)</span><br />
<br />
Anything that generates forms of that kind is going to be welcomed. You could even implement and use your own macros in there, provided that they generate that kind of code.<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">defstruct</span> also has a similar contract...<br />
<br />
<h4>
The <span style="font-family: "courier new" , "courier" , monospace;">defstruct</span> common contract</h4>
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (defstruct #export Int/Number (Number Int)
(do-template [<name> <op>]
[(def (<name> x y) (<op> x y))]
[+ _jvm_ladd]
[- _jvm_lsub]
[* _jvm_lmul]
[/ _jvm_ldiv]
[% _jvm_lrem])
(def (from-int x)
x)
(def (negate x)
(_jvm_lmul -1 x))
(def (abs x)
(if (_jvm_llt x 0)
(_jvm_lmul -1 x)
x))
(def (signum x)
(cond (_jvm_leq x 0) 0
(_jvm_llt x 0) -1
## else
1))
)
</code></pre>
<br />
In this case, what <span style="font-family: "courier new" , "courier" , monospace;">defstruct</span> is looking for is forms that define things.<br />
Note that, the <span style="font-family: "courier new" , "courier" , monospace;">def</span> macro being used here is the very same one used to define everything else in Lux.<br />
<br />
<b><i>Pretty cool, huh?</i></b><br />
<br />
Finally, there's one last piece of macro awesomeness I want to share before we call it quits.<br />
I came with it fairly recently, so I haven't settled on a name yet.<br />
For now, let's just call it <span style="font-family: "courier new" , "courier" , monospace;">let%</span><br />
<br />
Before I explain how it works, I'll show the itch it's meant cure:<br />
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (defstruct #export Json/Read (Read Json)
(def (read input)
(case (:: JsonNull/Read (read input))
(#;Some value)
(#;Some (#Null value))
#;None
(case (:: JsonBoolean/Read (read input))
(#;Some value)
(#;Some (#Boolean value))
#;None
(case (:: JsonNumber/Read (read input))
(#;Some value)
(#;Some (#Number value))
#;None
(case (:: JsonString/Read (read input))
(#;Some value)
(#;Some (#String value))
#;None
(case (:: (JsonArray/Read [read]) (read input))
(#;Some value)
(#;Some (#Array value))
#;None
(case (:: (JsonObject/Read [read]) (read input))
(#;Some value)
(#;Some (#Object value))
#;None
#;None))))))
))
</code></pre>
<br />
Do you see <b><i>that</i></b>? That <i><b>train-wreck</b></i>? That <i><b>monstrosity</b></i>?<br />
<br />
It's from a JSON library for Lux I'm working on.<br />
The <span style="font-family: "courier new" , "courier" , monospace;">Read</span> signature in Lux is for structures that try to parse something out of text. If they fail, you get <span style="font-family: "courier new" , "courier" , monospace;">#None</span><br />
<br />
As you can see, I'm having to do some testing, to try to figure out what I'm parsing, but the code is ruled by repetitive <span style="font-family: "courier new" , "courier" , monospace;">case</span> expressions where everything is the same, except what <i>parser</i> I'm using and what <i>tag</i> to give to the result.<br />
<br />
Surely, there must be a better way of doing it!<br />
<br />
First... let's flatten the structure:<br />
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (defstruct #export Json/Read (Read Json)
(def (read input)
(|> #;None
(case (:: (JsonObject/Read [read]) (read input))
(#;Some value)
(#;Some (#Object value))
#;None
)
(case (:: (JsonArray/Read [read]) (read input))
(#;Some value)
(#;Some (#Array value))
#;None
)
(case (:: JsonString/Read (read input))
(#;Some value)
(#;Some (#String value))
#;None
)
(case (:: JsonNumber/Read (read input))
(#;Some value)
(#;Some (#Number value))
#;None
)
(case (:: JsonBoolean/Read (read input))
(#;Some value)
(#;Some (#Boolean value))
#;None
)
(case (:: JsonNull/Read (read input))
(#;Some value)
(#;Some (#Null value))
#;None
))
))
</code></pre>
<br />
This might not be much, but it's a start.<br />
By using the piping macro <span style="font-family: "courier new" , "courier" , monospace;">|></span>, I can avoid all the nesting and keep all the tests in the same level.<br />
Now it's even more obvious that every form in there has the same shape, minus the <i>parser</i> and the <i>tag</i>.<br />
<br />
Man... wouldn't it be nice of we just had a macro for repeating things, while passing in parameters...<br />
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (defstruct #export Json/Read (Read Json)
(def (read input)
(|> #;None
(do-template [<struct> <tag>]
[(case (:: <struct> (read input))
(#;Some value)
(#;Some (<tag> value))
#;None
)]
[(JsonObject/Read [read]) #Object]
[(JsonArray/Read [read]) #Array]
[JsonString/Read #String]
[JsonNumber/Read #Number]
[JsonBoolean/Read #Boolean]
[JsonNull/Read #Null]))
))
</code></pre>
<br />
<span style="font-family: "courier new" , "courier" , monospace;">do-template</span> seems like a pretty wise choice here, doesn't it?<br />
The problem is that it doesn't play well with <span style="font-family: "courier new" , "courier" , monospace;">|></span>, as <span style="font-family: "courier new" , "courier" , monospace;">|></span> doesn't do any kind of macro-expansion of it's member forms prior to piping them.<br />
Because of that, I can't combine <span style="font-family: "courier new" , "courier" , monospace;">|></span> with <span style="font-family: "courier new" , "courier" , monospace;">do-template</span>; as awesome as that might be.<br />
<br />
<h4>
<span style="font-family: "courier new" , "courier" , monospace;">
let%</span> to the rescue</h4>
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (defstruct #export Json/Read (Read Json)
(def (read input)
(let% [<tests> (do-template [<struct> <tag>]
[(case (:: <struct> (read input))
(#;Some value)
(#;Some (<tag> value))
#;None
)]
[(JsonObject/Read [read]) #Object]
[(JsonArray/Read [read]) #Array]
[JsonString/Read #String]
[JsonNumber/Read #Number]
[JsonBoolean/Read #Boolean]
[JsonNull/Read #Null])]
(|> #;None
<tests>))
))
</code></pre>
<br />
<span style="font-family: Courier New, Courier, monospace;">let%</span> is meant for those situations in which you want to expand certain parts of the bodies of macros prior to expanding outer macros.With <span style="font-family: Courier New, Courier, monospace;">let%</span>, you can bind symbols to arbitrary amounts of forms produced by macro expansions, and then they're going to be spliced wherever the symbols appear, further down the line.<br />
<br />
With this, I can do all of my parsing while only focusing on the common logic and the details that change.<br />
<br />
<b>Note</b>: <span style="font-family: Courier New, Courier, monospace;">let%</span> is just a temporary name until I come up with something better.<br />
Do you have any suggestion? <i>Leave it in the comments</i>.<br />
And, yes, I have already considered <span style="font-family: Courier New, Courier, monospace;">with-macro-expansions</span>, but it's too damned long...<br />
<br />
_____________________________________________________________________________<br />
<br />
That's it for today.<br />
I know it was a long post, but hopefully you'll now understand the amazing power that can be unlocked when you write macros that play well together.<br />
<br />
See you next time :D<br />
<br />Eduardo Juliánhttp://www.blogger.com/profile/16436429020274670468noreply@blogger.com0tag:blogger.com,1999:blog-3344891259234150808.post-83056296843683799732015-11-05T14:50:00.002-08:002015-11-05T14:50:56.486-08:00Lux's values, types, signatures & structuresHello, and welcome to the 2nd entry in the <b>Lux Devlog</b>, a blog dedicated to the design and implementation of the <i>Lux Programming Language</i>, an upcoming functional language in the <i>Lisp</i> tradition.<br />
<br />
Today I'll touch 4 topics that are essential to the functioning & structure of Lux programs. You'll also learn about some of the unconventional language design involved in Lux and how to use these features.<br />
<br />
Without further ado, let's begin!<br />
<br />
<h2>
<b>Values</b></h2>
<br />
Lux gives you 5 different kinds of base values and 3 different kinds of composite values. This is besides having access to whatever types of objects the host-platform provides.<br />
<br />
First, we've got the <span style="font-family: Courier New, Courier, monospace;">Bool</span> type, with only two member values: <span style="font-family: Courier New, Courier, monospace;">true</span> and <span style="font-family: Courier New, Courier, monospace;">false</span>.<br />
<br />
Second, we've got the <span style="font-family: Courier New, Courier, monospace;">Int</span> type. Right now, it ranges over the values in Java's long type.<br />
<br />
Third, we've got the <span style="font-family: Courier New, Courier, monospace;">Real</span> type. It ranges over the values offered by Java's double type.<br />
<br />
Fourth, we've got the <span style="font-family: Courier New, Courier, monospace;">Char</span> type. It's syntax is a little unconventional; they look like these: <span style="font-family: Courier New, Courier, monospace;">#"a"</span>, <span style="font-family: Courier New, Courier, monospace;">#"\n"</span>, <span style="font-family: Courier New, Courier, monospace;">#"3".</span><br />
<br />
Fifth, we've got the <span style="font-family: Courier New, Courier, monospace;">Text</span> type. It's basically just strings, and has <span style="font-family: Courier New, Courier, monospace;">"the same conventional syntax everyone is used to"</span>.<br />
<br />
Regarding the composite values, Lux offers variants, tuples and records (or sums and products, as they're also called; with records being a kind of product).<br />
<br />
Tuples always look the same; just a sequence of values encased in brackets, like this one: <span style="font-family: Courier New, Courier, monospace;">[1 true "YOLO"].</span><br />
There's a special tuple called "unit", it's special because all instances are identical. The reason for that is simple: it's empty <span style="font-family: Courier New, Courier, monospace;">[]</span>.<br />
<br />
Variants are structures containing 2 elements: a <i>tag</i> and a <i>value</i>; like this: <span style="font-family: Courier New, Courier, monospace;">(#Some 123)</span><br />
If the value is unit, you can write something like <span style="font-family: Courier New, Courier, monospace;">(#None [])</span>, or, for convenience, you can just write <span style="font-family: Courier New, Courier, monospace;">#None</span>.<br />
If you're trying to associate more than 1 value with a tag, you'll need to use tuples for that. An example is the <i>#Cons</i> tag: <span style="font-family: Courier New, Courier, monospace;">(#Cons [head tail])</span><br />
However (also for convenience), you can omit the brackets and Lux will infer you're using a tuple when it sees more than 1 element following the tag. E.g. <span style="font-family: Courier New, Courier, monospace;">(#Cons head tail)</span><br />
<br />
Finally, we have to talk about records. Their syntax looks like this: <span style="font-family: Courier New, Courier, monospace;">{#foo 1 #bar true #baz "YOLO"}</span><br />
The order in which you specify the fields doesn't matter to the compiler.<br />
<br />
Records, I must reveal, are special among all of the value-types that I have mentioned, in that they only exist as a syntactic structure. In reality, all records are translated to tuples.<br />
<br />
Now that I have talked about these fairly simple & easy concepts, let's complicate things a bit. Let's talk about why the basic data-types have unconventional names, what are tags and how Lux stores variants & tuples.<br />
<br />
<h4>
What's the deal with the names?</h4>
<br />
You might find it annoying that I'm using the terms Bool, Int, Real, Char and Text for stuff that already has names within the Java platform (Boolean, Integer, Double, Character and String). The reason for me doing so has to do with portability.<br />
<br />
Here's the thing: I'm designing Lux so it's easy to port to other platforms. Because of that, I had to make a few choices regarding what can or can't be done in Lux, and how you do it.<br />
<br />
One thing you might have noticed if you were careful is that I never mention that Lux has support for floats (only for doubles). The same is true for bytes, shorts & ints (the 32-bit variety). That must look strange, coming from a language with a JVM compiler.<br />
<br />
Well... the first thing is that you <i><b>can</b></i> use all of those types; Lux just doesn't give you literal syntax for making them, so you have to resort to casting (there are a bunch of casting special forms in Lux, like <span style="font-family: Courier New, Courier, monospace;">_jvm_l2i</span>, a.k.a. long to int).<br />
<br />
The second thing is that I can't rely on all platforms offering that much variety in terms of datatypes, so Lux was designed to rely on as few data-types as possible.<br />
<br />
The funny thing is that, even the amount of types Lux has is too much for some platforms (consider that JavaScript lacks both chars & ints). However, those 5 basic types seemed like a good enough set.<br />
<br />
Finally, there's the issue of the names (sorry that it took me so long to actually talk about the subject of this subsection :P )<br />
<br />
Since Lux's 5 basic types are meant to shield you from the details of what the host platform provides, there wasn't any reason to base their names on the types of any one platform (remember that, for instance, JS has Number, rather than Int or Float). So, I got creative, I kept the names short and I fixed (in my opinion) some historical mistakes (floats were renamed as reals because a type's name should reflect it's meaning, rather than it's implementation; and strings were renamed as text because... well... nothing else made sense).<br />
<br />
<h4>
What the hell are tags?</h4>
<br />
This is a very important question, considering that this is a Lisp we're talking about.<br />
First things first: tags are not Lux's equivalent to Lisp keywords. Lux doesn't even have an equivalent to keywords.<br />
<br />
Tags are, in reality, nothing more than glorified ints.<br />
That's it. There you have it, folks. Now you know Lux's deep, dark secret.<br />
<br />
<i><u>Wait... ints? What the heck is going on here!?</u></i><br />
<br />
Ok, ok, ok. Here's what's going on: you can't use tags before you declare them and when you declare them, they get assigned int values. We'll talk more about declaring tags in the Types section.<br />
Suffice it to say that ints make it possible for Lux to do efficient pattern-matching on variants, since it's faster than comparing text tags, and it also makes it possible to reorder records as tuples, since you always know where every field needs to go.<br />
<br />
<h4>
How does Lux store variants & tuples?</h4>
<br />
Some of you might be familiar with Scala and think that, just like that language, Lux must create classes every time you define new data-types.<br />
If you think that, you're dead wrong.<br />
<br />
You shouldn't feel bad about it, though. I almost went down a similar road in the early days of Lux's design. Eventually, though, I came up with a much simpler model: arrays.<br />
<br />
It's very simple, really: n-tuples are just n-arrays, while variants are 2-arrays (index 0 is reserved for the tag, index 1 is for the value).<br />
<br />
<h2>
Types</h2>
<br />
Types are very interesting in Lux, for a few reasons:<br />
<ul>
<li>They are first-class objects</li>
<li>They are structural, rather than nominal</li>
<li>If you know what you're doing, you can do awesome things with them</li>
</ul>
<br /><ul>
</ul>
<h4>
First-class types</h4>
<br />
The trick to do this is to make types using the very same data-types I discussed in the previous section, and to allow the compiler to evaluate those data-structures and incorporate them into the type-checking phase.<br />
<br />
To find out how to make types, let's first check out their <i>type</i>:<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (deftype #rec Type
(| (#DataT Text (List Type))
(#VariantT (List Type))
(#TupleT (List Type))
(#LambdaT Type Type)
(#BoundT Int)
(#VarT Int)
(#ExT Int)
(#UnivQ (List Type) Type)
(#ExQ (List Type) Type)
(#AppT Type Type)
(#NamedT Ident Type)
))
</code></pre>
<br />
<span style="font-family: Courier New, Courier, monospace;">#DataT</span> is for representing host-platform types. It includes the name of the type and any type parameters it might have (if it is, for instance, a generic type in Java).<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">#VariantT</span> and <span style="font-family: Courier New, Courier, monospace;">#TupleT</span> require a list of all the member types (you might wonder where tags enter the mix, but I'll explain that soon enough).<br />
<br />
All functions in Lux are curried, so they only take a single argument. That's the reason behind <span style="font-family: Courier New, Courier, monospace;">#LambdaT</span> only having a type for it's input, and a type for it's output.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">#BoundT</span> represents a De Bruijn index, useful when working with both univeral and existential quantification (what <span style="font-family: Courier New, Courier, monospace;">#UnivQ</span> and <span style="font-family: Courier New, Courier, monospace;">#ExQ</span> are for).<br />
<br />
Also, the lists of types in <span style="font-family: Courier New, Courier, monospace;">#UnivQ</span> and <span style="font-family: Courier New, Courier, monospace;">#ExQ</span> represent their captured context (types with multiple parameters are also curried and require context for that).<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">#VarT</span> is a type variable. The int it holds serves to look up types inside a context when the compiler is doing type-checking.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">#ExT</span> is for existential types. Instances can only match when they have the same number.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">#AppT</span> is for applying universally-quantified types to parameters.<br />
<br />
Finally, <span style="font-family: Courier New, Courier, monospace;">#NamedT</span> is a convenient tool for giving names to types (helpful for debugging and documentation purposes).<br />
<br />
Now, you might be puzzled that there's a <span style="font-family: Courier New, Courier, monospace;">#rec</span> tag in from of the <span style="font-family: Courier New, Courier, monospace;">Type</span> definition. The reason is that types are not recursive by default and <span style="font-family: Courier New, Courier, monospace;">#rec</span> allows <span style="font-family: Courier New, Courier, monospace;">deftype</span> to perform a <i>minor cosmetic rearrangement</i> on your type to make it recursive.<br />
<br />
Another thing that <span style="font-family: Courier New, Courier, monospace;">deftype</span> does is to (automatically) wrap your type definitions inside <span style="font-family: Courier New, Courier, monospace;">#NamedT</span> so you don't have to worry about it.<br />
<br />
A final thing that it does is declare the tags referenced in your type. The int values each would get would depend on the order in which they appear, beginning with index 0 (tags cannot have negative values). The next time Lux sees the <span style="font-family: Courier New, Courier, monospace;">#TupleT</span><span style="font-family: inherit;"> tag</span>, it will know it actually means 2.<br />
<br />
Now, quick trivia for the curious:<br />
<b>Q</b>: <i>Does that mean that I can actually use ints instead of tags when writing variants?</i><br />
<br />
<b>A</b>: <i>Yes. In fact, if you check out the lux.lux (prelude) file, that's exactly what I do at the beginning to define types, as the tags for <span style="font-family: Courier New, Courier, monospace;">Type</span> & <span style="font-family: Courier New, Courier, monospace;">List</span> aren't defined at the very beginning.</i><br />
<i><br /></i>
<h4>
Structural, rather than nominal types</h4>
<br />
This should be obvious just from looking at the definition of <span style="font-family: Courier New, Courier, monospace;">Type</span>.<br />
An interesting consequence of this is that, since types are just Lux data-structures, I can pattern-match against them and get useful information.<br />
<br />
<h4>
Doing awesome stuff with types</h4>
<br />
The Lux compiler stores a lot of useful information regarding types. For instance, you can know the type of every definition in any module that has been compiled, and you can also ask which tags are associated to which types.<br />
<br />
You'll see some examples of what that enables in the next section.<br />
<br />
<h2>
Signatures & Structures</h2>
<br />
Lux handles polymorphism the same way that ML does, via signatures and structures.<br />
Think of signatures as interfaces that describe what a suitable implementation should provide.<br />
Structures are those implementations.<br />
<br />
Here is one example:<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (defsig #export (Functor f)
(: (All [a b] (-> (-> a b) (f a) (f b)))
map)) </code></pre>
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (defstruct #export List/Functor (Functor List)
(def (map f fa)
(case fa
#;Nil #;Nil
(#;Cons a fa') (#;Cons (f a) (map f fa'))))) </code></pre>
One difference between ML languages and Lux is that ML separates signatures and structures from the rest of the language, whereas Lux piggybacks on plain-old types and values in order to implement them.<br />
<br />
How? By using record/tuple-types as signatures and records as structures.<br />
The conversion is performed by the <span style="font-family: Courier New, Courier, monospace;">defsig</span> and <span style="font-family: Courier New, Courier, monospace;">defstruct</span> macros, which only serve to provide a more pleasant syntax for working with signatures & structures.<br />
<br />
Without the sugar they provide, our previous example would look like this:<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (deftype (Functor f)
(& #map (All [a b] (-> (-> a b) (f a) (f b)))
)) </code></pre>
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (def List/Functor
(Functor List)
{#map (lambda map [f fa]
(case fa
#;Nil #;Nil
(#;Cons a fa') (#;Cons (f a) (map f fa'))))
}) </code></pre>
_____________________________________________________________________________<br />
<br />
Lux offers many ways to work with structures in an easy way, depending on what you're trying to do.<br />
<br />
If you want to work with a structure inside a local scope, use the <span style="font-family: Courier New, Courier, monospace;">using</span> macro:<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (using List/Monoid
(foldL ++ unit list-of-lists)) </code></pre>
If you want to work with a structure in several places throughout a module, use the <span style="font-family: Courier New, Courier, monospace;">open</span> macro:<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (open List/Fold) </code></pre>
If you only want to use a specific element in a structure, use the <span style="font-family: Courier New, Courier, monospace;">::</span> macro:<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (:: Text/Eq (= x y))
(:: List/Monoid unit) </code></pre>
Also, remember when I told you that the Lux compiler stores a lot of type information? Those macros access that information to do their magic. They find out what are the names of the necessary tags and create all the code to generate lexical bindings, full-blown definitions, or just simple access code.<br />
<br />
<h2>
Bonus content: get@, set@ and update@</h2>
<br />
Oh... I almost forgot. There's one last bit I want to share with you.<br />
Remember records? They're really nice and all, but in order to access their contents you have to pattern-match on them.<br />
<br />
As you can imagine, pattern-matching on an record with 8 fields is not going to be nice, even if you do it in tuple-form.<br />
<br />
For that reason, there are 3 simple macros that take care of a lot of the complexity for you.<br />
<br />
<i>get@</i> allows you to access a single field from a record:<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (get@ #;modules state) </code></pre>
<i>set@</i> allows you to set a single field from a record:<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (set@ #pl;name "Lux" lang) </code></pre>
<i>update@</i> allows you to transform a single field from a record:<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (update@ #;seed (i:+ 1) state) </code></pre>
Again, these macros access the type information in the compiler to generate all the pattern-matching and record-building code necessary to perform these operations.<br />
<br />
_____________________________________________________________________________<br />
<br />
I'm sorry that the post was so long, but I wanted to be thorough.<br />
<br />
Next week is going to be pretty awesome, as I'm going to talk about custom-pattern matching & advanced macrology in Lux.<br />
<br />Eduardo Juliánhttp://www.blogger.com/profile/16436429020274670468noreply@blogger.com6tag:blogger.com,1999:blog-3344891259234150808.post-81777656181716700942015-10-04T21:56:00.003-07:002015-10-26T15:03:09.621-07:00Macros in LuxHello, and welcome to the first entry in the <b>Lux Devlog</b>, wherein the posts will touch the design and implementation of the <i>Lux Programming Language</i>, an upcoming functional language in the <i>Lisp</i> tradition.<br />
<br />
To begin this series of posts, I'll talk about a subject I've been asked before by curious programmers: <i>why is it that Lux macros are monadic?</i><br />
<br />
I'll expand on that subject a bit and talk about all of the machinery that Lux offers in terms of macros.<br />
<div>
<br /></div>
<div>
First, I've got a disclaimer to make: <b>this is not a monads tutorial</b>. There are many tutorials out there and this blog post isn't the right place to introduce the subject. With that in mind, let's move on...</div>
<div>
<br />
The reason why Lux macros are monadic has to do with the fact that they operate inside a special context in the compiler in which they get to have access to its state. That is one of the privileges of running during compile-time, and it gives them access to a lot of really useful information regarding modules, types, global definitions and much more.<br />
<br /></div>
<div>
To understand how everything is wired together, it's a good idea to check out the types of the things we are going to be dealing with:</div>
<div>
<br /></div>
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (deftype (Lux a)
(-> Compiler (Either Text (, Compiler a))))
</code></pre>
<div>
<br /></div>
<div>
The type above is the type of functions that work with access to the state of the compiler.</div>
<div>
<br /></div>
<div>
For those of you unfamiliar with the syntax (pretty much everybody, as Lux is fairly new), the <span style="font-family: Courier New, Courier, monospace;"><b>-></b></span> sign is a macro for specifying functions; the <span style="font-family: Courier New, Courier, monospace;"><b>,</b></span> sign serves to specify tuples; and <span style="font-family: Courier New, Courier, monospace;"><b>(Lux a)</b></span> specifies a polymorphic type with 1 parameter (named <span style="font-family: Courier New, Courier, monospace;"><b>a</b></span>).</div>
<div>
<br /></div>
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (deftype Macro
(-> (List AST) (Lux (List AST))))
</code></pre>
<div>
<br /></div>
<div>
Macros are functions that, given a list of syntactic tokens (as instances of the AST type), they must return a function that can have access to the state of the compiler and must return an updated list of tokens.</div>
<div>
<br /></div>
<div>
<i>But... what does Lux ASTs look like?</i></div>
<div>
Well... they're data-structures like any other:</div>
<div>
<br /></div>
<div>
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;">## This isn't the way it's defined, but it's good for explaining it...
(deftype #rec AST
(Meta Cursor
(| (#BoolS Bool)
(#IntS Int)
(#RealS Real)
(#CharS Char)
(#TextS Text)
(#SymbolS Text Text)
(#TagS Text Text)
(#FormS (List AST))
(#TupleS (List AST))
(#RecordS (List (, AST AST))))))
</code></pre>
</div>
<div>
<br /></div>
<div>
Again, for those of you unfamiliar with the syntax, the hash (<span style="font-family: Courier New, Courier, monospace;"><b>#)</b></span> sign is used to specify the tags for variants (a.k.a. sum types). The pipe (<span style="font-family: Courier New, Courier, monospace;"><b>|</b></span>) sign is what declares that the following cases belong to a variant type. Also, the <span style="font-family: Courier New, Courier, monospace;"><b>#rec</b></span> tag that is added before AST declares that it's a recursive type, so that you can refer to it by name inside it's own definition.</div>
<div>
<br /></div>
<div>
Also, you might wonder what <b><span style="font-family: Courier New, Courier, monospace;">Meta</span></b> & <b><span style="font-family: Courier New, Courier, monospace;">Cursor</span></b> are for. Well, the answer is very simple: AST nodes don't come alone, as they carry with them some meta-data (that's what <span style="font-family: Courier New, Courier, monospace;"><b>Meta</b></span> is for), which, in this case, just happens to be a cursor that points to the place in the source code where said AST has it's text representation.</div>
<div>
<br /></div>
<div>
<i>What does that cursor look like?</i><br />
Let's take a look:</div>
<div>
<br /></div>
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (deftype Cursor (, Text Int Int))
</code></pre>
<div>
<br /></div>
<div>
It's just a 3-tuple where the first element corresponds to the name of the file, the second element corresponds to the line, and the third element corresponds to the column.</div>
<div>
<br /></div>
<div>
Finally, let's take a look at what the compiler offers:<br />
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (deftype #rec Compiler
(& #source Source
#cursor Cursor
#modules (List (, Text (Module Compiler)))
#envs (List (Env Text (Meta (, Type Cursor) Analysis)))
#type-vars (Bindings Int Type)
#expected Type
#seed Int
#eval? Bool
#host Void
))
</code></pre>
<br /></div>
<div>
<br /></div>
<div>
So... it's a fairly complex data-structure with yet more new type-syntax to deal with.</div>
<div>
<br /></div>
<div>
We can already recognize the <b><span style="font-family: Courier New, Courier, monospace;">#rec</span></b> tag, but what's up with the ampersand?</div>
<div>
Well... that ampersand (<b><span style="font-family: Courier New, Courier, monospace;">&</span></b>) is what signifies that this type correspond to records. The tags being matched to their respective types do not require to be put inside parenthesis, and are instead matched as pairs.</div>
<div>
<br /></div>
<div>
While there are many new types being mentioned, they will be left for future blog-posts, as right now we're going to focus more on macros per se. Suffice it to say that the Lux compiler accumulates a lot information and that's what the <span style="font-family: Courier New, Courier, monospace;"><b>Compiler</b></span> type embodies.</div>
<div>
<br /></div>
<div>
_____________________________________________________________________________</div>
<div>
<br />
Some of you might have noticed that macros are not expected to return one AST token, but can return an arbitrary amount, as their return type involves <b><span style="font-family: Courier New, Courier, monospace;">(List AST)</span></b>.<br />
<br />
This is one of the places where Lux differs from more traditional lisps, where macros always return one piece of syntax.<br />
<br />
While in most cases that is all you'll need to return from a macro, sometimes you do want to return more than 1 elements (or, as is the case for the <b><span style="font-family: Courier New, Courier, monospace;">comment</span></b> macro, no elements).<br />
<br />
So... what does a macro definition in Lux look like?<br />
Let's check out how the <b><span style="font-family: Courier New, Courier, monospace;">@list</span></b> macro is defined inside the <span style="font-family: Courier New, Courier, monospace;"><b>lux/data/list</b></span> module:<br />
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (defmacro #export (@list xs state)
(#;Right state (#;Cons (foldL (: (-> AST AST AST)
(lambda [tail head] (` (#;Cons (~ head) (~ tail)))))
(` #;Nil)
(reverse xs))
#;Nil)))
</code></pre>
<br />
There's a lot of new stuff in that snippet.<br />
<br />
Besides seeing that there's already an easy way to define macros and an even easier way to export definitions, we can also see that macros receive the state of the compiler as an argument (we already expected that from the type definition).<br />
<br />
We can also notice what's the syntax for creating variants in Lux (just put the tag at the beginning of a form and the data afterwards), the syntax for adding type annotations to code (<b><span style="font-family: Courier New, Courier, monospace;">:</span></b>), and the syntax for quasi-quotation (<span style="font-family: Courier New, Courier, monospace;"><b>`</b></span>) and unquoting (<span style="font-family: Courier New, Courier, monospace;">~</span>).<br />
<br />
Some lispers might be wondering why quotation code is written in this style:<br />
<pre style="background: rgb(240, 240, 240); border: 1px dashed rgb(204, 204, 204); font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; width: 646.46875px;"><code style="word-wrap: normal;">(` (#;Cons (~ head) (~ tail)))</code></pre>
instead of in this style:<br />
<pre style="background: rgb(240, 240, 240); border: 1px dashed rgb(204, 204, 204); font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; width: 646.46875px;"><code style="word-wrap: normal;">`(#;Cons ~head ~tail)</code></pre>
<br />
The reason for that is this: quasi-quotation in Lux is done via a regular macro, instead of via a reader-macro, as is done on most lisps.<br />
<br />
Since quotation was going to have that kind of syntax in Lux, there wasn't any reason for unquoting to be different, and that's why it all looks like that.<br />
<br />
It's different to what most lispers are accustomed to, but it doesn't take long for someone to get used to it.<br />
<br />
Ok... so, the <b><span style="font-family: Courier New, Courier, monospace;">@list</span></b> example is nice, but there's no analysis of the incoming syntax tokens. How do I write complex macros that actually do something with the arguments?<br />
<br />
Well... let's check out another example:<br />
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (defmacro #export (do-template tokens)
(case tokens
(#Cons [_ (#TupleS bindings)]
(#Cons [_ (#TupleS templates)]
data))
(case [(map% Maybe/Monad get-name bindings)
(map% Maybe/Monad tuple->list data)]
[(#Some bindings') (#Some data')]
(let [apply (: (-> RepEnv (List AST))
(lambda [env]
(map (apply-template env)
templates)))]
(|> data'
(join-map (. apply (make-env bindings')))
return))
_
(fail "Wrong syntax for do-template"))
_
(fail "Wrong syntax for do-template")))
</code></pre>
<br />
The example above comes from the <b><span style="font-family: Courier New, Courier, monospace;">lux</span></b> module (the prelude), and is the definition of the (very useful) <b><span style="font-family: Courier New, Courier, monospace;">do-template</span></b> macro (which I'll touch on briefly before the end of this blog post).<br />
<br />
As you can see, the syntax tokens are being decomposed through pattern-matching, extracting, in this case, a pair of tuples and some "data" that is processed later.<br />
<br />
Also, some of you might notice that <span style="font-family: Courier New, Courier, monospace;"><b>do-template</b></span> is not receiving the state of the compiler, as was the case for <b><span style="font-family: Courier New, Courier, monospace;">@list</span></b>. What's happening here is that <span style="font-family: Courier New, Courier, monospace;"><b>do-template</b></span> is making use of 2 functions (<span style="font-family: Courier New, Courier, monospace;"><b>return</b></span> & <span style="font-family: Courier New, Courier, monospace;"><b>fail</b></span>), that generate functions that do take the state of the compiler (<span style="font-family: Courier New, Courier, monospace;"><b>return</b></span> takes the state and then returns whatever data you gave to it, while <span style="font-family: Courier New, Courier, monospace;"><b>fail</b></span> takes the state but ignores it to just send back an error message).<br />
<br />
Again, there are many details here that will be left for future blog-posts, but you can already see that extracting data from the AST tokens is not the nicest thing in the world.<br />
<br />
Just consider for a moment the hassle that it would be to extract many different arguments, some of them being optional or repetitive, or embedded inside larger syntactic structures.<br />
<br />
How could someone write complex macros in a simple way using Lux?<br />
<br />
The answer turns out to be very easy, but it's something that many lispers might not have experience with: <i>monadic parsing</i>.<br />
<br />
<b><span style="font-family: Courier New, Courier, monospace;">What!? More monads!?</span></b><br />
<br />
Calm down. There's no need to panic. Monadic parsing is a very simple technique for writing parsers as functions that take tokens of some type and return tokens of another, higher-level type.<br />
<br />
By using monadic parsers inside of macros, it's possible to specify very complex parsing rules in very simple ways that can even be reused across macros.<br />
<br />
Another really cool benefit, is that you can return custom data-structures from these parsers, further elevating your macros into a more domain-specific level and taking into consideration optional and repetitive elements of the AST tokens being parsed.<br />
<br />
An example of how that's supposed to look like is this macro, taken from the <span style="font-family: Courier New, Courier, monospace;"><b>lux/host/jvm</b></span> module:<br />
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (defsyntax #export (defclass [name local-symbol^] [super local-symbol^] [interfaces (tuple^ (*^ local-symbol^))]
[annotations annotations^]
[fields (*^ field-decl^)]
[methods (*^ method-def^)])
(emit (@list (` (;_jvm_class (~ (text$ name)) (~ (text$ super))
[(~@ (map text$ interfaces))]
[(~@ (map gen-annotation annotations))]
[(~@ (map gen-field-decl fields))]
[(~@ (map gen-method-def methods))])))))
</code></pre>
<br />
You'll notice that now I'm using <span style="font-family: Courier New, Courier, monospace;"><b>defsyntax</b></span> instead of <b><span style="font-family: Courier New, Courier, monospace;">defmacro</span></b>. You'll also notice that the arguments that the macro takes are specified in a very different manner, with the names of the arguments being paired with parsers (the name of each being suffixed with a caret ^) and some being prefixed by a strange symbol (<b><span style="font-family: Courier New, Courier, monospace;">*^</span></b>), which turns out to be a parser combinator that means <i>0 or more</i>.<br />
<br />
Also, you'll see that I'm using unquote-splice (<span style="font-family: Courier New, Courier, monospace;"><b>~@</b></span>) to handle the output of the map function being invoked several times. Finally, the <b><span style="font-family: Courier New, Courier, monospace;">emit</span></b> function you see is the same as <b><span style="font-family: Courier New, Courier, monospace;">return</span></b> in the example of <span style="font-family: Courier New, Courier, monospace;"><b>do-template</b></span>. (I won't go into detail here as to why the names are different).<br />
<br />
This macro is still complex, but only because what it tries to do is complex in and out of itself. This macro provides a more pleasant syntax to class declaration than what Lux natively exposes through the <b><span style="font-family: Courier New, Courier, monospace;">_jvm_class</span></b> special form.<br />
<br />
However, by abstracting out how annotations, fields and methods are parsed, not only have I simplified the code of this macro, but I can even reuse those parsing mechanisms in other macros, such as the macro for making anonymous classes or the macro for making interfaces.<br />
<br />
Not only that, but each of those parsers returns a different data-type, custom made for the information that it represents. That way, my macros are not confined to only work with the raw data that the AST tokens provide, but can instead work with more refined and domain-specific representations of that data.<br />
<br />
While monadic parsers on macros might be a new thing for many lispers out there, after using them for a while for writing some macros, of both low & medium complexity, I must say the they are probably the best technique I've found for managing complexity when writing macros. They're a pleasure to use and it doesn't take much effort to become proficient in their use.<br />
<br />
_____________________________________________________________________________<br />
<br />
Finally, I would like to touch on something I promised a while ago...<br />
<br />
Sometimes, you want to generate code in a very limited manner and creating a macro to do it seems a bit like overkill. Maybe you're just looking for a way to repeat a particular pattern in code that doesn't require any serious processing of the arguments. For those kinds of situations, you'll want to use the <b><span style="font-family: Courier New, Courier, monospace;">do-template</span></b> macro.<br />
<br />
For those of you who are familiar with it's <i>Clojure</i> counterpart, the <b><span style="font-family: Courier New, Courier, monospace;">do-template</span></b> macro works the same way, with a small difference being the way it takes its arguments. What do I mean? Let's take a look at an example:<br />
<br />
<pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> (do-template [<name> <diff>]
[(def #export <name>
(-> Int Int)
(i+ <diff>))]
[inc 1]
[dec -1])
</code></pre>
<br />
Here we see code for generating the <span style="font-family: Courier New, Courier, monospace;"><b>inc</b></span> & <span style="font-family: Courier New, Courier, monospace;"><b>dec</b></span> functions (both available in the <b><span style="font-family: Courier New, Courier, monospace;">lux</span></b> module). As you can see, the form for the pattern is inside a tuple. The reason for that is that there can be more than 1 form in there, so the tuple delimits all the forms that must be generated for every group of parameters.<br />
<br />
You'll also see that each group of parameters is also delimited by tuple syntax. The goal of that is to make it better ordered when you're passing arguments to the template.<br />
<br />
By the way, the fact that the arguments to the template are surrounded by <angle> <brackets> is just a stylistic choice of mine and not a requirement of <b><span style="font-family: Courier New, Courier, monospace;">do-template</span></b>.<br />
<br />
_____________________________________________________________________________<br />
<br />
That's all that I wanted to say for now concerning macros in Lux.<br />
<br />
There are more things that could be explained about this subject, but I'll leave those for future blog posts.<br />
<br /></div>
Eduardo Juliánhttp://www.blogger.com/profile/16436429020274670468noreply@blogger.com0