<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Data.Random &#187; Axman6</title>
	<atom:link href="http://random.axman6.com/blog/?feed=rss2&#038;author=1" rel="self" type="application/rss+xml" />
	<link>http://random.axman6.com/blog</link>
	<description>Random mutterings about life and Haskell.</description>
	<lastBuildDate>Fri, 06 Jul 2012 05:21:54 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>AusHac2010: The inaugural Australian Haskell Hackathon!</title>
		<link>http://random.axman6.com/blog/?p=153</link>
		<comments>http://random.axman6.com/blog/?p=153#comments</comments>
		<pubDate>Mon, 22 Mar 2010 22:12:57 +0000</pubDate>
		<dc:creator>Axman6</dc:creator>
				<category><![CDATA[Haskell]]></category>

		<guid isPermaLink="false">http://random.axman6.com/blog/?p=153</guid>
		<description><![CDATA[Over the last week or so, Ivan Miljenovic and I have been busy organising AusHac2010. We&#8217;ve made a lot of progress, and are announcing the dates as the 16th-18th of July. If you&#8217;d like to come along and work on projects like:


    The LLVM backend to GHC
    the Accelerate, [...]]]></description>
			<content:encoded><![CDATA[<p>Over the last week or so, Ivan Miljenovic and I have been busy organising AusHac2010. We&#8217;ve made a lot of progress, and are announcing the dates as the 16th-18th of July. If you&#8217;d like to come along and work on projects like:</p>

<ul>
    <li>The LLVM backend to GHC</li>
    <li>the Accelerate, a Haskell EDSL for regular array computations, using various backends (CUDA, OpenCL, LLVM etc.) </li>
    <li> Hubris, the Haskell-Ruby binding</li>
    <li>Leksah, the Haskell IDE written in Haskell</li>
    <li>MPI bindings</li>
</ul>

<p>then please put your name down on the <a href="http://axman6.wufoo.com/forms/aushac-2010-sign-up/">sign up page</a>.</p>

<p>This should be a great opportunity for Aussie (and non aussie!) haskell hackers to come and meet all those people you know from Planet Haskell and #haskell, and give something back to the community, while having a great time.</p>

<p>Hope to see you there,
&#8211; Alex Mason</p>
]]></content:encoded>
			<wfw:commentRss>http://random.axman6.com/blog/?feed=rss2&amp;p=153</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A small follow up</title>
		<link>http://random.axman6.com/blog/?p=139</link>
		<comments>http://random.axman6.com/blog/?p=139#comments</comments>
		<pubDate>Thu, 07 Jan 2010 14:39:05 +0000</pubDate>
		<dc:creator>Axman6</dc:creator>
				<category><![CDATA[Haskell]]></category>
		<category><![CDATA[bittorrent]]></category>
		<category><![CDATA[cereal]]></category>
		<category><![CDATA[parsing]]></category>

		<guid isPermaLink="false">http://random.axman6.com/blog/?p=139</guid>
		<description><![CDATA[In my previous post about why I love the cereal package, I went through the development of a bencoding parser and encoder. Brian was kind enough to point out some of the flaws I&#8217;d made in this code (which I should add had been caused from me not actually checking the spec while writing the [...]]]></description>
			<content:encoded><![CDATA[<p>In my previous post about why I love the cereal package, I went through the development of a bencoding parser and encoder. Brian was kind enough to point out some of the flaws I&#8217;d made in this code (which I should add had been caused from me not actually checking the spec while writing the code, obviously a bad idea), and from these comments, I think I&#8217;ve managed to fix most of the problems:</p>

<blockquote>
Hi, thanks for writing this stuff. I think it could be pretty cool, but it could benefit from more precise reading and implementation of the spec.
<br/><br/>
For example, bencoded integers can be negative.
<br/><br/>
Also, my alarms go off whenever I see ‘read’. In ‘getBString’, you pass ‘read count’ to ‘getByteString’, which expects Int. But check, e.g., ‘read (show $ 2^64-1) :: Int’ in ghci. So if the torrent data is malformed, you could end up passing a negative length to ‘getByteString’. Maybe it knows how to deal with that, but it’s not something you should rely on.
<br/><br/>
You also have to decide what to do about dictionaries you read whose keys aren’t in order, etc.
<br/><br/>
Basically, please be more precise, especially if you put this on Hackage. This stuff is supposed to be industrial strength. Thanks.
</blockquote>

<p>The first problem, not handling negative integers was pretty trivial to fix, all I needed to do was check to see if there was a &#8216;-&#8217; char out the front, and if not, just get all the digits, and then read them:</p>

<p><pre><span class='hs-comment'>-- | Parses a BInt</span>
<span class='hs-definition'>getBInt</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Get</span> <span class='hs-conid'>BCode</span>
<span class='hs-definition'>getBInt</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>BInt</span> <span class='hs-varop'>.</span> <span class='hs-varid'>read</span> <span class='hs-varop'>&lt;$&gt;</span> <span class='hs-varid'>getWrapped</span> <span class='hs-chr'>'i'</span> <span class='hs-chr'>'e'</span> <span class='hs-varid'>intP</span>
    <span class='hs-keyword'>where</span> <span class='hs-varid'>intP</span> <span class='hs-keyglyph'>=</span> <span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-conop'>:</span><span class='hs-layout'>)</span> <span class='hs-varop'>&lt;$&gt;</span> <span class='hs-varid'>char</span> <span class='hs-chr'>'-'</span> <span class='hs-varop'>&lt;*&gt;</span> <span class='hs-varid'>getDigits</span><span class='hs-layout'>)</span> <span class='hs-varop'>&lt;|&gt;</span> <span class='hs-varid'>getDigits</span></pre></p>

<p>Brian also pointed out something I also wasn&#8217;t particularly happy with, the use of <code>read</code> to read in an Int64. This should under normal circumstances be more than large enough to read any bytestring that should be in any bencoded data (.torrent files are usually less than 1-200KB), so we should never have run into a problem here, but it&#8217;s still good to make sure we can be &#8216;industrial strength&#8217;:</p>

<p><pre><span class='hs-comment'>-- | Parses a BString</span>
<span class='hs-definition'>getBString</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Get</span> <span class='hs-conid'>BCode</span>
<span class='hs-definition'>getBString</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>
    <span class='hs-varid'>count</span> <span class='hs-keyglyph'>&lt;-</span> <span class='hs-varid'>getDigits</span>
    <span class='hs-conid'>BString</span> <span class='hs-varop'>&lt;$&gt;</span> <span class='hs-layout'>(</span> <span class='hs-varid'>char</span> <span class='hs-chr'>':'</span> <span class='hs-varop'>*&gt;</span> <span class='hs-varid'>getStr</span> <span class='hs-layout'>(</span><span class='hs-varid'>read</span> <span class='hs-varid'>count</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Integer</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span>
    <span class='hs-keyword'>where</span> <span class='hs-varid'>maxInt</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>fromIntegral</span> <span class='hs-layout'>(</span><span class='hs-varid'>maxBound</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Int</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Integer</span>
          <span class='hs-varid'>getStr</span> <span class='hs-varid'>n</span> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>n</span> <span class='hs-varop'>&gt;=</span> <span class='hs-num'>0</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>B</span><span class='hs-varop'>.</span><span class='hs-varid'>concat</span> <span class='hs-varop'>&lt;$&gt;</span> <span class='hs-layout'>(</span><span class='hs-varid'>sequence</span> <span class='hs-varop'>$</span> <span class='hs-varid'>getStr'</span> <span class='hs-varid'>n</span><span class='hs-layout'>)</span>
                   <span class='hs-keyglyph'>|</span> <span class='hs-varid'>otherwise</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>fail</span> <span class='hs-varop'>$</span> <span class='hs-str'>"read a negative length string, length: "</span> <span class='hs-varop'>++</span> <span class='hs-varid'>show</span> <span class='hs-varid'>n</span>
          <span class='hs-varid'>getStr'</span> <span class='hs-varid'>n</span> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>n</span> <span class='hs-varop'>&gt;</span> <span class='hs-varid'>maxInt</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>getByteString</span> <span class='hs-varid'>maxBound</span> <span class='hs-conop'>:</span> <span class='hs-varid'>getStr'</span> <span class='hs-layout'>(</span><span class='hs-varid'>n</span><span class='hs-comment'>-</span><span class='hs-varid'>maxInt</span><span class='hs-layout'>)</span>
                    <span class='hs-keyglyph'>|</span> <span class='hs-varid'>otherwise</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyglyph'>[</span><span class='hs-varid'>getByteString</span> <span class='hs-varop'>.</span> <span class='hs-varid'>fromIntegral</span> <span class='hs-varop'>$</span> <span class='hs-varid'>n</span><span class='hs-keyglyph'>]</span></pre></p>

<p>Here you can see we&#8217;re now using an <code>Integer</code> as the read value, and taking chunks of <code>maxBound :: Int</code> bytes, until there are less than that many bytes left to fetch.</p>

<p>I&#8217;ve decided to ignore the problem with dictionaries with out of order elements, I can see this being something others may have overlooked in their implementations, and it&#8217;s entirely possible that other implementations do not put the keys in the right order. Our implementation does, but can easily handle malformed implementations. I see this is a bonus, and I hope others do too (I feel the code is more robust, and that&#8217;s always good).</p>

<p>I hope this has made some difference to the code, and what people think of it.</p>

<p>Until next time,</p>

<p>&#8211; Axman</p>
]]></content:encoded>
			<wfw:commentRss>http://random.axman6.com/blog/?feed=rss2&amp;p=139</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Why I love Cereal</title>
		<link>http://random.axman6.com/blog/?p=124</link>
		<comments>http://random.axman6.com/blog/?p=124#comments</comments>
		<pubDate>Mon, 04 Jan 2010 15:11:08 +0000</pubDate>
		<dc:creator>Axman6</dc:creator>
				<category><![CDATA[Haskell]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[binary]]></category>
		<category><![CDATA[bittorrent]]></category>
		<category><![CDATA[cereal]]></category>
		<category><![CDATA[parsing]]></category>

		<guid isPermaLink="false">http://random.axman6.com/blog/?p=124</guid>
		<description><![CDATA[Cereal, as you may know from my previous posts is a library for parsing binary data from strict ByteStrings. It is very similar to the binary package, but importantly, provides both an Alternative instance, and an Either String a return type for the decode function, which tells you where the parse failed.

I’ve been playing around [...]]]></description>
			<content:encoded><![CDATA[<p>Cereal, as you may know from my previous posts is a library for parsing binary data from strict ByteStrings. It is very similar to the binary package, but importantly, provides both an Alternative instance, and an <code>Either String a</code> return type for the decode function, which tells you where the parse failed.</p>

<p>I’ve been playing around with cereal lately in jlouis’ haskell-torrent project, rewriting the various binary parsing and producing parts of the program (the torrent file parser, and the wire protocol parser). I though it would be nice to share some of the code used for these, to demonstrate how easy cereal makes it to do such things.</p>

<p>To begin with, I’ll show you the part that decodes and encodes torrent files (if needed in the future). Torrent files are encoded using a very simple encoding, known as bencoding, which consists of four major primitives: Integral numbers, Strings of bytes, Arrays of bencoded objects, and Dictionaries of String, bencoded object pairs. This is very nicely represented using this datatype:
<pre><span class="hs-comment">-- | BCode represents the structure of a bencoded file</span>
<span class="hs-keyword">data</span> <span class="hs-conid">BCode</span> <span class="hs-keyglyph">=</span> <span class="hs-conid">BInt</span> <span class="hs-conid">Integer</span>                       <span class="hs-comment">-- ^ An integer</span>
           <span class="hs-keyglyph">|</span> <span class="hs-conid">BString</span> <span class="hs-conid">B</span><span class="hs-varop">.</span><span class="hs-conid">ByteString</span>               <span class="hs-comment">-- ^ A string of bytes</span>
           <span class="hs-keyglyph">|</span> <span class="hs-conid">BArray</span> <span class="hs-keyglyph">[</span><span class="hs-conid">BCode</span><span class="hs-keyglyph">]</span>                     <span class="hs-comment">-- ^ An array</span>
           <span class="hs-keyglyph">|</span> <span class="hs-conid">BDict</span> <span class="hs-layout">(</span><span class="hs-conid">M</span><span class="hs-varop">.</span><span class="hs-conid">Map</span> <span class="hs-conid">B</span><span class="hs-varop">.</span><span class="hs-conid">ByteString</span> <span class="hs-conid">BCode</span><span class="hs-layout">)</span>   <span class="hs-comment">-- ^ A key, value map</span>
  <span class="hs-keyword">deriving</span> <span class="hs-conid">Show</span></pre>
the specification for bencoded data goes something like this:</p>

<blockquote>Integers are encoded as the ASCII character for ‘i’ as a byte,
followed by the digits of the integral value, terminated by the
ASCII byte for ‘e’.
<blockquote>Eg: the number ‘42’ would be encoded as &#8220;i42e&#8221;</blockquote>
Strings are encoded as the digits of their length, followed by a
colon (‘:’), then the bytes of the string. these strings are really
just byte sequences, and probably shouldn’t be treated as having
an encoding (as jlouis and I found out when I tried to test the current
code on GHC 6.12.1, with the BString type using Strings, instead of
ByteStrings, and finding out that the simple test contained byte sequences
that could not be represented as Strings).
<blockquote>Eg: the string &#8220;hello&#8221; would become &#8220;5:hello&#8221;, &#8220;hello world&#8221; would
become &#8220;11:hello world&#8221;</blockquote>
Arrays are encoded as ASCII ‘l’ (for list I believe), followed by any
number of bencoded objects, terminated by an ASCII ‘e’. (This is where
using binary became difficult, as you had to explicitly check whether
you had reached the terminating ‘e’ using <code>lookAhead</code> when parsing before attempting
to parse another bencoded object, du the the lack of actual failure handling)
<blockquote>Eg: ["Hello", 123] would become &#8220;l5:helloi123ee&#8221;. Notice how we’ve used the
previous definitions for integral numbers, and strings.</blockquote>
Dictionaries are encoded as an ASCII ‘d’, followed by the String, object
pairs, followed by an ASCII ‘e’.
<blockquote>Eg: fromList [("test",123),("arr",[1,2,"hello"])] would become
&#8220;d4:testi123e3:arrli1ei2e5:helloee&#8221;.</blockquote>
It looks a bit of a mess, but it is quite efficient.</blockquote>

<h3 id="encoding">Encoding</h3>

<p>When writing my Serialize instance (Cereal’s version of the Binary class) for the BCode type, I decided it would be much easier to write the put methods first. This turned out to be rather straight forward, once I’d written a few helper functions.
<pre><span class="hs-definition">toW8</span> <span class="hs-keyglyph">::</span> <span class="hs-conid">Char</span> <span class="hs-keyglyph">-&gt;</span> <span class="hs-conid">Word8</span>
<span class="hs-definition">toW8</span> <span class="hs-keyglyph">=</span> <span class="hs-varid">fromIntegral</span> <span class="hs-varop">.</span> <span class="hs-varid">ord</span></p>

<p><span class="hs-definition">fromW8</span> <span class="hs-keyglyph">::</span> <span class="hs-conid">Word8</span> <span class="hs-keyglyph">-&gt;</span> <span class="hs-conid">Char</span>
<span class="hs-definition">fromW8</span> <span class="hs-keyglyph">=</span> <span class="hs-varid">chr</span> <span class="hs-varop">.</span> <span class="hs-varid">fromIntegral</span></p>

<p><span class="hs-definition">toBS</span> <span class="hs-keyglyph">::</span> <span class="hs-conid">String</span> <span class="hs-keyglyph">-&gt;</span> <span class="hs-conid">B</span><span class="hs-varop">.</span><span class="hs-conid">ByteString</span>
<span class="hs-definition">toBS</span> <span class="hs-keyglyph">=</span> <span class="hs-conid">B</span><span class="hs-varop">.</span><span class="hs-varid">pack</span> <span class="hs-varop">.</span> <span class="hs-varid">map</span> <span class="hs-varid">toW8</span></p>

<p><span class="hs-definition">fromBS</span> <span class="hs-keyglyph">::</span> <span class="hs-conid">B</span><span class="hs-varop">.</span><span class="hs-conid">ByteString</span> <span class="hs-keyglyph">-&gt;</span> <span class="hs-conid">String</span>
<span class="hs-definition">fromBS</span> <span class="hs-keyglyph">=</span> <span class="hs-varid">map</span> <span class="hs-varid">fromW8</span> <span class="hs-varop">.</span> <span class="hs-conid">B</span><span class="hs-varop">.</span><span class="hs-varid">unpack</span></p>

<p><span class="hs-comment">-- | Put an element, wrapped by two characters</span>
<span class="hs-definition">wrap</span> <span class="hs-keyglyph">::</span> <span class="hs-conid">Char</span> <span class="hs-keyglyph">-&gt;</span> <span class="hs-conid">Char</span> <span class="hs-keyglyph">-&gt;</span> <span class="hs-conid">Put</span> <span class="hs-keyglyph">-&gt;</span> <span class="hs-conid">Put</span>
<span class="hs-definition">wrap</span> <span class="hs-varid">a</span> <span class="hs-varid">b</span> <span class="hs-varid">m</span> <span class="hs-keyglyph">=</span> <span class="hs-keyword">do</span>
    <span class="hs-varid">putWord8</span> <span class="hs-layout">(</span><span class="hs-varid">toW8</span> <span class="hs-varid">a</span><span class="hs-layout">)</span>
    <span class="hs-varid">m</span>
    <span class="hs-varid">putWord8</span> <span class="hs-layout">(</span><span class="hs-varid">toW8</span> <span class="hs-varid">b</span><span class="hs-layout">)</span></p>

<p><span class="hs-comment">-- | Put something as it is shown using @show@</span>
<span class="hs-definition">putShow</span> <span class="hs-keyglyph">::</span> <span class="hs-conid">Show</span> <span class="hs-varid">a</span> <span class="hs-keyglyph">=&gt;</span> <span class="hs-varid">a</span> <span class="hs-keyglyph">-&gt;</span> <span class="hs-conid">Put</span>
<span class="hs-definition">putShow</span> <span class="hs-varid">x</span> <span class="hs-keyglyph">=</span> <span class="hs-varid">mapM_</span> <span class="hs-varid">put</span> <span class="hs-layout">(</span><span class="hs-varid">show</span> <span class="hs-varid">x</span><span class="hs-layout">)</span></pre>
With these in hand, I set to work implementing the put function. The Integer and Array functions were straight forward:
<pre><span class="hs-keyword">instance</span> <span class="hs-conid">Serialize</span> <span class="hs-conid">BCode</span> <span class="hs-keyword">where</span>
     <span class="hs-varid">put</span> <span class="hs-layout">(</span><span class="hs-conid">BInt</span> <span class="hs-varid">i</span><span class="hs-layout">)</span>     <span class="hs-keyglyph">=</span> <span class="hs-varid">wrap</span> <span class="hs-chr">'i'</span> <span class="hs-chr">'e'</span> <span class="hs-varop">$</span> <span class="hs-varid">putShow</span> <span class="hs-varid">i</span>
     <span class="hs-varid">put</span> <span class="hs-layout">(</span><span class="hs-conid">BArray</span> <span class="hs-varid">arr</span><span class="hs-layout">)</span> <span class="hs-keyglyph">=</span> <span class="hs-varid">wrap</span> <span class="hs-chr">'l'</span> <span class="hs-chr">'e'</span> <span class="hs-varop">.</span> <span class="hs-varid">mapM_</span> <span class="hs-varid">put</span> <span class="hs-varop">$</span> <span class="hs-varid">arr</span></pre>
The Dictionary and String implementations weren’t too bad either:
<pre>    <span class="hs-varid">put</span> <span class="hs-layout">(</span><span class="hs-conid">BDict</span> <span class="hs-varid">mp</span><span class="hs-layout">)</span>   <span class="hs-keyglyph">=</span> <span class="hs-varid">wrap</span> <span class="hs-chr">'d'</span> <span class="hs-chr">'e'</span> <span class="hs-varid">dict</span>
                      <span class="hs-keyword">where</span> <span class="hs-varid">dict</span> <span class="hs-keyglyph">=</span> <span class="hs-varid">mapM_</span> <span class="hs-varid">encPair</span> <span class="hs-varop">.</span> <span class="hs-conid">M</span><span class="hs-varop">.</span><span class="hs-varid">toList</span> <span class="hs-varop">$</span> <span class="hs-varid">mp</span>
                            <span class="hs-varid">encPair</span> <span class="hs-layout">(</span><span class="hs-varid">k</span><span class="hs-layout">,</span> <span class="hs-varid">v</span><span class="hs-layout">)</span> <span class="hs-keyglyph">=</span> <span class="hs-varid">put</span> <span class="hs-layout">(</span><span class="hs-conid">BString</span> <span class="hs-varid">k</span><span class="hs-layout">)</span> <span class="hs-varop">&gt;&gt;</span> <span class="hs-varid">put</span> <span class="hs-varid">v</span>
     <span class="hs-varid">put</span> <span class="hs-layout">(</span><span class="hs-conid">BString</span> <span class="hs-varid">s</span><span class="hs-layout">)</span>  <span class="hs-keyglyph">=</span> <span class="hs-keyword">do</span>
                          <span class="hs-varid">putShow</span> <span class="hs-layout">(</span><span class="hs-conid">B</span><span class="hs-varop">.</span><span class="hs-varid">length</span> <span class="hs-varid">s</span><span class="hs-layout">)</span>
                          <span class="hs-varid">putWord8</span> <span class="hs-layout">(</span><span class="hs-varid">toW8</span> <span class="hs-chr">':'</span><span class="hs-layout">)</span>
                          <span class="hs-varid">putByteString</span> <span class="hs-varid">s</span></pre>
As you can see, the code is quite clear, and matches the specification quite well.</p>

<h3 id="decoding">Decoding</h3>

<p>Parsing the data was the next step. this proved a little more difficult, but with my recent (shallow) experience with Parsec, I knew what was needed.</p>

<p>I decided to start by writing some useful combinators (this is a lie, I wrote them when needed, but lying makes the post flow better &gt;_&gt;). These included the following:
<pre><span class="hs-comment">-- | Get a Char. Only works with single byte characters</span>
 <span class="hs-definition">getCharG</span> <span class="hs-keyglyph">::</span> <span class="hs-conid">Get</span> <span class="hs-conid">Char</span>
 <span class="hs-definition">getCharG</span> <span class="hs-keyglyph">=</span> <span class="hs-varid">fromW8</span> <span class="hs-varop">&lt;$&gt;</span> <span class="hs-varid">getWord8</span></p>

<p><span class="hs-comment">-- | Parse a given character</span>
 <span class="hs-definition">char</span> <span class="hs-keyglyph">::</span> <span class="hs-conid">Char</span> <span class="hs-keyglyph">-&gt;</span> <span class="hs-conid">Get</span> <span class="hs-conid">()</span>
 <span class="hs-definition">char</span> <span class="hs-varid">c</span> <span class="hs-keyglyph">=</span> <span class="hs-keyword">do</span>
     <span class="hs-varid">x</span> <span class="hs-keyglyph">&lt;-</span> <span class="hs-varid">getCharG</span>
     <span class="hs-keyword">if</span> <span class="hs-varid">x</span> <span class="hs-varop">==</span> <span class="hs-varid">c</span>
         <span class="hs-keyword">then</span> <span class="hs-varid">return</span> <span class="hs-conid">()</span>
         <span class="hs-keyword">else</span> <span class="hs-varid">fail</span> <span class="hs-varop">$</span> <span class="hs-str">"Expected char: '"</span> <span class="hs-varop">++</span> <span class="hs-varid">c</span><span class="hs-conop">:</span><span class="hs-str">"' got: '"</span> <span class="hs-varop">++</span> <span class="hs-keyglyph">[</span><span class="hs-varid">fromW8</span> <span class="hs-varid">x</span><span class="hs-layout">,</span><span class="hs-chr">'\''</span><span class="hs-keyglyph">]</span></p>

<p><span class="hs-comment">-- | Get something wrapped in two Chars</span>
 <span class="hs-definition">getWrapped</span> <span class="hs-keyglyph">::</span> <span class="hs-conid">Char</span> <span class="hs-keyglyph">-&gt;</span> <span class="hs-conid">Char</span> <span class="hs-keyglyph">-&gt;</span> <span class="hs-conid">Get</span> <span class="hs-varid">a</span> <span class="hs-keyglyph">-&gt;</span> <span class="hs-conid">Get</span> <span class="hs-varid">a</span>
 <span class="hs-definition">getWrapped</span> <span class="hs-varid">a</span> <span class="hs-varid">b</span> <span class="hs-varid">p</span> <span class="hs-keyglyph">=</span> <span class="hs-varid">char</span> <span class="hs-varid">a</span> <span class="hs-varop"><em>&gt;</span> <span class="hs-varid">p</span> <span class="hs-varop">&lt;</em></span> <span class="hs-varid">char</span> <span class="hs-varid">b</span>
                  <span class="hs-comment">-- The same as char a &gt;&gt; p &gt;&gt;= \x -&gt; char b &gt;&gt; return x</span></p>

<p><span class="hs-comment">-- | Parse zero or items using a given parser</span>
 <span class="hs-definition">many</span> <span class="hs-keyglyph">::</span> <span class="hs-conid">Get</span> <span class="hs-varid">a</span> <span class="hs-keyglyph">-&gt;</span> <span class="hs-conid">Get</span> <span class="hs-keyglyph">[</span><span class="hs-varid">a</span><span class="hs-keyglyph">]</span>
 <span class="hs-definition">many</span> <span class="hs-varid">p</span> <span class="hs-keyglyph">=</span> <span class="hs-varid">many1</span> <span class="hs-varid">p</span> <span class="hs-varop"><code>mplus</code></span> <span class="hs-varid">return</span> <span class="hs-conid">[]</span></p>

<p><span class="hs-comment">-- | Parse one or more items using a given parser</span>
 <span class="hs-definition">many1</span> <span class="hs-keyglyph">::</span> <span class="hs-conid">Get</span> <span class="hs-varid">a</span> <span class="hs-keyglyph">-&gt;</span> <span class="hs-conid">Get</span> <span class="hs-keyglyph">[</span><span class="hs-varid">a</span><span class="hs-keyglyph">]</span>
 <span class="hs-definition">many1</span> <span class="hs-varid">p</span> <span class="hs-keyglyph">=</span> <span class="hs-layout">(</span><span class="hs-conop">:</span><span class="hs-layout">)</span> <span class="hs-varop">&lt;$&gt;</span> <span class="hs-varid">p</span> <span class="hs-varop">&lt;*&gt;</span> <span class="hs-varid">many</span> <span class="hs-varid">p</span></p>

<p><span class="hs-comment">-- | Returns a character if it is a digit, fails otherwise. uses isDigit.</span>
 <span class="hs-definition">digit</span> <span class="hs-keyglyph">::</span> <span class="hs-conid">Get</span> <span class="hs-conid">Char</span>
 <span class="hs-definition">digit</span> <span class="hs-keyglyph">=</span> <span class="hs-keyword">do</span>
     <span class="hs-varid">x</span> <span class="hs-keyglyph">&lt;-</span> <span class="hs-varid">getCharG</span>
     <span class="hs-keyword">if</span> <span class="hs-varid">isDigit</span> <span class="hs-varid">x</span>
         <span class="hs-keyword">then</span> <span class="hs-varid">return</span> <span class="hs-varid">x</span>
         <span class="hs-keyword">else</span> <span class="hs-varid">fail</span> <span class="hs-varop">$</span> <span class="hs-str">"Expected digit, got: "</span> <span class="hs-varop">++</span> <span class="hs-varid">show</span> <span class="hs-varid">x</span></p>

<p><span class="hs-comment">-- | Get one or more digit characters</span>
 <span class="hs-definition">getDigits</span> <span class="hs-keyglyph">::</span> <span class="hs-conid">Get</span> <span class="hs-conid">String</span>
 <span class="hs-definition">getDigits</span> <span class="hs-keyglyph">=</span> <span class="hs-varid">many1</span> <span class="hs-varid">digit</span></pre>
My favourite two definitions here are <code>many</code> and <code>many1</code>, which nicely show the use of Alternative: they are mutually recursive, with <code>many1</code> being the only one of the two to actually do and parsing, while <code>many</code> checks to see if <code>many1</code> failed to parse one object using the parser p. It’s really quite beautiful, and makes the code that follows a hell of a lot nicer to write. This is where the love mentioned in the title comes in by the way.</p>

<p>With these in hand, I could now go ahead and write the actual parsers for various BCode types. Parsing BInts and BArrays is dead simple now:
<pre><span class="hs-comment">-- | Parses a BInt</span>
 <span class="hs-definition">getBInt</span> <span class="hs-keyglyph">::</span> <span class="hs-conid">Get</span> <span class="hs-conid">BCode</span>
 <span class="hs-definition">getBInt</span> <span class="hs-keyglyph">=</span> <span class="hs-conid">BInt</span> <span class="hs-varop">.</span> <span class="hs-varid">read</span> <span class="hs-varop">&lt;$&gt;</span> <span class="hs-varid">getWrapped</span> <span class="hs-chr">'i'</span> <span class="hs-chr">'e'</span> <span class="hs-varid">getDigits</span></p>

<p><span class="hs-comment">-- | Parses a BArray</span>
 <span class="hs-definition">getBArray</span> <span class="hs-keyglyph">::</span> <span class="hs-conid">Get</span> <span class="hs-conid">BCode</span>
 <span class="hs-definition">getBArray</span> <span class="hs-keyglyph">=</span> <span class="hs-conid">BArray</span> <span class="hs-varop">&lt;$&gt;</span> <span class="hs-varid">getWrapped</span> <span class="hs-chr">'l'</span> <span class="hs-chr">'e'</span> <span class="hs-layout">(</span><span class="hs-varid">many</span> <span class="hs-varid">get</span><span class="hs-layout">)</span></pre>
As as side note, I’ve now come to see just what the folks on #haskell were on about when they said Applicative is nice. I think I’ve fallen in love (yet again!).</p>

<p>BStrings were a little more difficult, but not hard, given what I’ve just written:
<pre><span class="hs-comment">-- | Parses a BString</span>
 <span class="hs-definition">getBString</span> <span class="hs-keyglyph">::</span> <span class="hs-conid">Get</span> <span class="hs-conid">BCode</span>
 <span class="hs-definition">getBString</span> <span class="hs-keyglyph">=</span> <span class="hs-keyword">do</span>
     <span class="hs-varid">count</span> <span class="hs-keyglyph">&lt;-</span> <span class="hs-varid">getDigits</span>
     <span class="hs-conid">BString</span> <span class="hs-varop">&lt;$&gt;</span> <span class="hs-layout">(</span> <span class="hs-varid">char</span> <span class="hs-chr">':'</span> <span class="hs-varop">*&gt;</span> <span class="hs-varid">getByteString</span> <span class="hs-layout">(</span><span class="hs-varid">read</span> <span class="hs-varid">count</span><span class="hs-layout">)</span><span class="hs-layout">)</span></pre>
Here we get as many digits as we can, followed by a colon, and then take the number of bytes the digits specified. Finally, we have the BDict definition, which also is quite nice, if slightly annoying with its use of pattern matching (don’t get me wrong, i love pattern matching, but it’s the only place it’s used in the parser <img src='http://random.axman6.com/blog/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' />  )
<pre><span class="hs-comment">-- | Parses a BDict</span>
 <span class="hs-definition">getBDict</span> <span class="hs-keyglyph">::</span> <span class="hs-conid">Get</span> <span class="hs-conid">BCode</span>
 <span class="hs-definition">getBDict</span> <span class="hs-keyglyph">=</span> <span class="hs-conid">BDict</span> <span class="hs-varop">.</span> <span class="hs-conid">M</span><span class="hs-varop">.</span><span class="hs-varid">fromList</span> <span class="hs-varop">&lt;$&gt;</span> <span class="hs-varid">getWrapped</span> <span class="hs-chr">'d'</span> <span class="hs-chr">'e'</span> <span class="hs-layout">(</span><span class="hs-varid">many</span> <span class="hs-varid">getPairs</span><span class="hs-layout">)</span>
     <span class="hs-keyword">where</span> <span class="hs-varid">getPairs</span> <span class="hs-keyglyph">=</span> <span class="hs-keyword">do</span>
             <span class="hs-layout">(</span><span class="hs-conid">BString</span> <span class="hs-varid">s</span><span class="hs-layout">)</span> <span class="hs-keyglyph">&lt;-</span> <span class="hs-varid">getBString</span>
             <span class="hs-varid">x</span> <span class="hs-keyglyph">&lt;-</span> <span class="hs-varid">get</span>
             <span class="hs-varid">return</span> <span class="hs-layout">(</span><span class="hs-varid">s</span><span class="hs-layout">,</span><span class="hs-varid">x</span><span class="hs-layout">)</span></pre>
Putting it all together, we finally have a definition for the get function in the Serialize class.
<pre>    <span class="hs-varid">get</span> <span class="hs-keyglyph">=</span> <span class="hs-varid">getBInt</span> <span class="hs-varop">&lt;|&gt;</span> <span class="hs-varid">getBArray</span> <span class="hs-varop">&lt;|&gt;</span> <span class="hs-varid">getBDict</span> <span class="hs-varop">&lt;|&gt;</span> <span class="hs-varid">getBString</span></pre>
A rather clean, elegant, and hopefully correct serialiser and deserialiser for the bencoded format used in torrent files. I’m considering releasing this code as a separate package on hackage, but I’m still not sure how widely it might be used. I have a string feeling that that would not be very wide at all, but that a library of more advanced combinators for cereal would make life a lot easier for others like me who have some strange binary formats that need to be parsed in an efficient manner.</p>

<p>Please, I implore you, do let me know what you think of this all, I’m always interested in seeing what others think of my code, and ways to improve it.</p>

<p>Until next time,</p>

<p>— Axman</p>
]]></content:encoded>
			<wfw:commentRss>http://random.axman6.com/blog/?feed=rss2&amp;p=124</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Playing with Haskell-Torrent</title>
		<link>http://random.axman6.com/blog/?p=121</link>
		<comments>http://random.axman6.com/blog/?p=121#comments</comments>
		<pubDate>Fri, 01 Jan 2010 14:05:15 +0000</pubDate>
		<dc:creator>Axman6</dc:creator>
				<category><![CDATA[Haskell]]></category>
		<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://random.axman6.com/blog/?p=121</guid>
		<description><![CDATA[Over the last week or so, I&#8217;ve been playing around with some of the minor details of jlouis&#8217; Haskell-Torrent code. The main pieces I&#8217;ve been playing with have been the more binary centric pieces: the torrent file en/decoding and since Wednesday, the wire protocol.

After trying to compile the code using GHC 6.12.1, I noticed that [...]]]></description>
			<content:encoded><![CDATA[<p>Over the last week or so, I&#8217;ve been playing around with some of the minor details of jlouis&#8217; Haskell-Torrent code. The main pieces I&#8217;ve been playing with have been the more binary centric pieces: the torrent file en/decoding and since Wednesday, the wire protocol.</p>

<p>After trying to compile the code using GHC 6.12.1, I noticed that a rather strange dependency: HCodecs. Investigating further, I realised that all that was being used was its fairly nice binary builder and parser, and was being used in the parsing and construction of bencoded files. This seemed to me to be the domain of one of my favourite packages, binary. I also noticed that when trying to parse the sample torrent file jlouis had provided, there was binary data that could not be represented in a String type, because there were byte sequences that could not be parses into Char&#8217;s.</p>

<p>So I went off to try and implement the BCode module using Data.Binary. The encoding was really simple and straight forward, but parsing was another matter. Binary has no real error handeling, which meant that decoding things like lists where you keep adding elements to the list until you reach an &#8216;e&#8217;, was made quite verbose due to this fact. After implementing a (semi) working module, I went in search of a more parsec like interface to binary parsing. This is when someone on #Haskell informed me of cereal, a package based on binary, which added an Alternative instance, and an Either String a return type for better error reporting.</p>

<p>I fell in love. This was exactly what I was after, I could create my own combinators like many and many1, with the same ease I could with parsec. Using cereal, I was able to make a really clear, concise parser, which should also be quite efficient.</p>

<p>I will post some of this code at a later time, when i&#8217;m not writing on my iPhone, and show you just what I mean. I&#8217;m also considering releasing the BCode module as a package of it&#8217;s own, if anyone else feels it might me useful to them. Either that, or I might write up a module of useful combinators for use with cereal.</p>

<p>Until next time, happy new year and I hope this year treats you all better than the last one did.</p>

<p>&#8211; Al</p>
]]></content:encoded>
			<wfw:commentRss>http://random.axman6.com/blog/?feed=rss2&amp;p=121</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Testing BlogLiterally, and HTML DSL changes</title>
		<link>http://random.axman6.com/blog/?p=113</link>
		<comments>http://random.axman6.com/blog/?p=113#comments</comments>
		<pubDate>Tue, 03 Nov 2009 07:13:41 +0000</pubDate>
		<dc:creator>Axman6</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://random.axman6.com/blog/?p=113</guid>
		<description><![CDATA[Robert Greayer has just released his BlogLiterally program on hackage, so I thought I&#8217;d try it out. I&#8217;ve made some small changes to the HTML DSL I&#8217;ve been working on since i last posted, which I&#8217;ll outline here:

The HTML type is now

data HTML a = Doctype String String String (HTML a)
     [...]]]></description>
			<content:encoded><![CDATA[<p>Robert Greayer has just released his BlogLiterally program on hackage, so I thought I&#8217;d try it out. I&#8217;ve made some small changes to the HTML DSL I&#8217;ve been working on since i last posted, which I&#8217;ll outline here:</p>

<p>The HTML type is now</p>

<p><pre><code><span style="color: blue; font-weight: bold;">data</span> <span style="">HTML</span> <span style="">a</span> <span style="color: red;">=</span> <span style="">Doctype</span> <span style="">String</span> <span style="">String</span> <span style="">String</span> <span style="color: red;">(</span><span style="">HTML</span> <span style="">a</span><span style="color: red;">)</span>
            <span style="color: red;">|</span> <span style="">Content</span> <span style="">a</span>
            <span style="color: red;">|</span> <span style="">Text</span> <span style="">String</span>
            <span style="color: red;">|</span> <span style="">Node</span> <span style="">Tag</span> <span style="">Attrs</span> <span style="color: red;">[</span><span style="">HTML</span> <span style="">a</span><span style="color: red;">]</span>
            <span style="color: red;">|</span> <span style="">NoContent</span> <span style="">Tag</span> <span style="">Attrs</span>
            <span style="color: red;">|</span> <span style="">Comment</span> <span style="">String</span>
            <span style="color: blue; font-weight: bold;">deriving</span> <span style="">Show</span></code></pre><p>instead of</p><pre><code><span style="color: blue; font-weight: bold;">data</span> <span style="">HTML</span> <span style="">a</span> <span style="color: red;">=</span> <span style="">Doctype</span> <span style="">String</span> <span style="">String</span> <span style="">String</span> <span style="color: red;">[</span><span style="">HTML</span> <span style="">a</span><span style="color: red;">]</span>
            <span style="color: red;">|</span> <span style="">Content</span> <span style="">a</span>
            <span style="color: red;">|</span> <span style="">Text</span> <span style="">String</span>
            <span style="color: red;">|</span> <span style="">Node</span> <span style="">Tag</span> <span style="">Attrs</span> <span style="color: red;">[</span><span style="">HTML</span> <span style="">a</span><span style="color: red;">]</span>
            <span style="color: red;">|</span> <span style="">NoContent</span> <span style="">Tag</span> <span style="">Attrs</span>
            <span style="color: red;">|</span> <span style="">Comment</span> <span style="">String</span>
            <span style="color: blue; font-weight: bold;">deriving</span> <span style="">Show</span></code></pre><p>I&#8217;ve also added some more helper functions:</p><pre><code><span style="">addAttrs</span> <span style="color: red;">::</span> <span style="">Attrs</span> <span style="color: red;">-&gt;</span> <span style="">HTML</span> <span style="">a</span> <span style="color: red;">-&gt;</span> <span style="">HTML</span> <span style="">a</span>
<span style="">addAttrs</span> <span style="">attrs</span> <span style="color: red;">(</span><span style="">Node</span> <span style="">tag</span> <span style="">attrs'</span> <span style="">rest</span><span style="color: red;">)</span> <span style="color: red;">=</span> <span style="">Node</span> <span style="">tag</span> <span style="color: red;">(</span><span style="">attrs'</span> <span style="">++</span> <span style="">attrs</span><span style="color: red;">)</span> <span style="">rest</span>
<span style="">addAttrs</span> <span style="">attrs</span> <span style="color: red;">(</span><span style="">NoContent</span> <span style="">tag</span> <span style="">attrs'</span><span style="color: red;">)</span> <span style="color: red;">=</span> <span style="">NoContent</span> <span style="">tag</span> <span style="color: red;">(</span><span style="">attrs'</span><span style="">++</span><span style="">attrs</span><span style="color: red;">)</span>
<span style="">addAttrs</span> <span style="color: blue; font-weight: bold;">_</span> <span style="">x</span> <span style="color: red;">=</span> <span style="">x</span></p>

<p><span style="">toTable</span> <span style="color: red;">::</span> <span style="color: red;">[</span><span style="color: red;">[</span><span style="">String</span><span style="color: red;">]</span><span style="color: red;">]</span> <span style="color: red;">-&gt;</span> <span style="">HTML</span> <span style="">a</span>
<span style="">toTable</span> <span style="">xss</span> <span style="color: red;">=</span> <span style="">table</span> <span style="">.</span> <span style="">map</span> <span style="color: red;">(</span><span style="">tr</span> <span style="">.</span> <span style="">map</span> <span style="color: red;">(</span><span style="color: red;">\</span><span style="">x</span> <span style="color: red;">-&gt;</span> <span style="">td</span> <span style="color: red;">[</span><span style="">text</span> <span style="">x</span><span style="color: red;">]</span><span style="color: red;">)</span><span style="color: red;">)</span> <span style="">$</span> <span style="">xss</span></p>

<p><span style="">toTable'</span> <span style="color: red;">::</span> <span style="">Show</span> <span style="">a</span> <span style="color: red;">=&gt;</span> <span style="color: red;">[</span><span style="color: red;">[</span><span style="">a</span><span style="color: red;">]</span><span style="color: red;">]</span> <span style="color: red;">-&gt;</span> <span style="">HTML</span> <span style="">b</span>
<span style="">toTable'</span> <span style="color: red;">=</span> <span style="">toTable</span> <span style="">.</span> <span style="">map</span> <span style="color: red;">(</span><span style="">map</span> <span style="">show</span><span style="color: red;">)</span></code></pre></p>

<p>And updated my example:</p>

<p><pre><code><span style="">example</span> <span style="color: red;">::</span> <span style="">HTML</span> <span style="">()</span>
<span style="">example</span> <span style="color: red;">=</span>
    <span style="">doctype</span> <span style="color: teal;">"html PUBLIC"</span>
            <span style="color: teal;">"-//W3C//DTD XHTML 1.0 Transitional//EN"</span>
            <span style="color: teal;">"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"</span> <span style="">$</span>
        <span style="">xhtml</span> <span style="color: red;">[</span>
            <span style="">header</span> <span style="color: red;">[</span>
                <span style="">title</span> <span style="color: teal;">"My random page"</span><span style="color: red;">,</span>
                <span style="">meta</span> <span style="color: teal;">"name"</span> <span style="color: teal;">"Alex"</span>
            <span style="color: red;">]</span><span style="color: red;">,</span>
            <span style="">body</span> <span style="color: red;">[</span>
                <span style="">comment</span> <span style="color: teal;">"This is a comment"</span><span style="color: red;">,</span>
                <span style="">para</span> <span style="color: red;">[</span>
                    <span style="">text</span> <span style="color: teal;">"The hr tag defines a horizontal rule:"</span>
                <span style="color: red;">]</span><span style="color: red;">,</span>
                <span style="">hr</span><span style="color: red;">,</span>
                <span style="">para</span> <span style="color: red;">[</span>
                    <span style="">text</span> <span style="color: teal;">"This is a paragraph"</span>
                <span style="color: red;">]</span><span style="color: red;">,</span>
                <span style="">hr</span><span style="color: red;">,</span>
                <span style="">para</span> <span style="color: red;">[</span>
                    <span style="">text</span> <span style="color: teal;">"This is a paragraph"</span>
                <span style="color: red;">]</span><span style="color: red;">,</span>
                <span style="">addAttrs</span> <span style="color: red;">[</span><span style="color: red;">(</span><span style="color: teal;">"border"</span><span style="color: red;">,</span><span style="color: teal;">"1px"</span><span style="color: red;">)</span><span style="color: red;">]</span> <span style="">.</span> <span style="">toTable'</span> <span style="">$</span> <span style="color: red;">[</span><span style="color: red;">[</span><span class="hs-num">0</span><span style="color: red;">..</span><span style="">n</span><span style="color: red;">]</span> <span style="color: red;">|</span> <span style="">n</span> <span style="color: red;">&lt;-</span> <span style="color: red;">[</span><span class="hs-num">0</span><span style="color: red;">..</span><span class="hs-num">3</span><span style="color: red;">]</span><span style="color: red;">]</span>
            <span style="color: red;">]</span>
        <span style="color: red;">]</span></code></pre><p>Which produces this html:</p><pre><code>    <span style="">&lt;!</span><span style="">DOCTYPE</span> <span style="">html</span> <span style="">PUBLIC</span> <span style="color: teal;">"-//W3C//DTD XHTML 1.0 Transitional//EN"</span>
       <span style="color: teal;">"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"</span><span style="">&gt;</span>
    <span style="">&lt;</span><span style="">html</span> <span style="">xmlns</span><span style="color: red;">=</span><span style="color: teal;">"http://www.w3.org/1999/xhtml"</span> <span style="">xml</span><span style="">:</span><span style="">lang</span><span style="color: red;">=</span><span style="color: teal;">"en"</span> <span style="">lang</span><span style="color: red;">=</span><span style="color: teal;">"en"</span><span style="">&gt;</span>
        <span style="">&lt;</span><span style="">head</span> <span style="">&gt;</span>
            <span style="">&lt;</span><span style="">title</span> <span style="">&gt;</span>
                <span style="">My</span> <span style="">random</span> <span style="">page</span>
            <span style="">&lt;/</span><span style="">title</span><span style="">&gt;</span>
            <span style="">&lt;</span><span style="">meta</span> <span style="">name</span><span style="color: red;">=</span><span style="color: teal;">"name"</span> <span style="">content</span><span style="color: red;">=</span><span style="color: teal;">"Alex"</span><span style="">/&gt;</span>
        <span style="">&lt;/</span><span style="">head</span><span style="">&gt;</span>
        <span style="">&lt;</span><span style="">body</span> <span style="">&gt;</span>
            <span style="">&lt;!--</span> <span style="">This</span> <span style="">is</span> <span style="">a</span> <span style="">comment</span> <span style="">--&gt;</span>
            <span style="">&lt;</span><span style="">p</span> <span style="">&gt;</span>
                <span style="">The</span> <span style="">hr</span> <span style="">tag</span> <span style="">defines</span> <span style="">a</span> <span style="">horizontal</span> <span style="">rule</span><span style="">:</span>
            <span style="">&lt;/</span><span style="">p</span><span style="">&gt;</span>
            <span style="">&lt;</span><span style="">hr</span> <span style="">/&gt;</span>
            <span style="">&lt;</span><span style="">p</span> <span style="">&gt;</span>
                <span style="">This</span> <span style="">is</span> <span style="">a</span> <span style="">paragraph</span>
            <span style="">&lt;/</span><span style="">p</span><span style="">&gt;</span>
            <span style="">&lt;</span><span style="">hr</span> <span style="">/&gt;</span>
            <span style="">&lt;</span><span style="">p</span> <span style="">&gt;</span>
                <span style="">This</span> <span style="">is</span> <span style="">a</span> <span style="">paragraph</span>
            <span style="">&lt;/</span><span style="">p</span><span style="">&gt;</span>
            <span style="">&lt;</span><span style="">table</span> <span style="">border</span><span style="color: red;">=</span><span style="color: teal;">"1px"</span><span style="">&gt;</span>
                <span style="">&lt;</span><span style="">tr</span> <span style="">&gt;</span>
                    <span style="">&lt;</span><span style="">td</span> <span style="">&gt;</span>
                        <span class="hs-num">0</span>
                    <span style="">&lt;/</span><span style="">td</span><span style="">&gt;</span>
                <span style="">&lt;/</span><span style="">tr</span><span style="">&gt;</span>
                <span style="">&lt;</span><span style="">tr</span> <span style="">&gt;</span>
                    <span style="">&lt;</span><span style="">td</span> <span style="">&gt;</span>
                        <span class="hs-num">0</span>
                    <span style="">&lt;/</span><span style="">td</span><span style="">&gt;</span>
                    <span style="">&lt;</span><span style="">td</span> <span style="">&gt;</span>
                        <span class="hs-num">1</span>
                    <span style="">&lt;/</span><span style="">td</span><span style="">&gt;</span>
                <span style="">&lt;/</span><span style="">tr</span><span style="">&gt;</span>
                <span style="">&lt;</span><span style="">tr</span> <span style="">&gt;</span>
                    <span style="">&lt;</span><span style="">td</span> <span style="">&gt;</span>
                        <span class="hs-num">0</span>
                    <span style="">&lt;/</span><span style="">td</span><span style="">&gt;</span>
                    <span style="">&lt;</span><span style="">td</span> <span style="">&gt;</span>
                        <span class="hs-num">1</span>
                    <span style="">&lt;/</span><span style="">td</span><span style="">&gt;</span>
                    <span style="">&lt;</span><span style="">td</span> <span style="">&gt;</span>
                        <span class="hs-num">2</span>
                    <span style="">&lt;/</span><span style="">td</span><span style="">&gt;</span>
                <span style="">&lt;/</span><span style="">tr</span><span style="">&gt;</span>
                <span style="">&lt;</span><span style="">tr</span> <span style="">&gt;</span>
                    <span style="">&lt;</span><span style="">td</span> <span style="">&gt;</span>
                        <span class="hs-num">0</span>
                    <span style="">&lt;/</span><span style="">td</span><span style="">&gt;</span>
                    <span style="">&lt;</span><span style="">td</span> <span style="">&gt;</span>
                        <span class="hs-num">1</span>
                    <span style="">&lt;/</span><span style="">td</span><span style="">&gt;</span>
                    <span style="">&lt;</span><span style="">td</span> <span style="">&gt;</span>
                        <span class="hs-num">2</span>
                    <span style="">&lt;/</span><span style="">td</span><span style="">&gt;</span>
                    <span style="">&lt;</span><span style="">td</span> <span style="">&gt;</span>
                        <span class="hs-num">3</span>
                    <span style="">&lt;/</span><span style="">td</span><span style="">&gt;</span>
                <span style="">&lt;/</span><span style="">tr</span><span style="">&gt;</span>
            <span style="">&lt;/</span><span style="">table</span><span style="">&gt;</span>
        <span style="">&lt;/</span><span style="">body</span><span style="">&gt;</span>
    <span style="">&lt;/</span><span style="">html</span><span style="">&gt;</span></code></pre></p>
]]></content:encoded>
			<wfw:commentRss>http://random.axman6.com/blog/?feed=rss2&amp;p=113</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>An HTML DSL in Haskell in one day</title>
		<link>http://random.axman6.com/blog/?p=104</link>
		<comments>http://random.axman6.com/blog/?p=104#comments</comments>
		<pubDate>Mon, 02 Nov 2009 04:44:19 +0000</pubDate>
		<dc:creator>Axman6</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://random.axman6.com/blog/?p=104</guid>
		<description><![CDATA[So, after a discussion on #haskell, I decided to try writing a simple HTML DSL in Haskell. In about 15 minutes, I had a rather rudimentary implementation, and after a day or so of working, I&#8217;ve got a somewhat useful DSL for writing HTML, and pretty printing it.

The main type behind the package is:

data HTML [...]]]></description>
			<content:encoded><![CDATA[<p>So, after a discussion on #haskell, I decided to try writing a simple HTML DSL in Haskell. In about 15 minutes, I had a rather rudimentary implementation, and after a day or so of working, I&#8217;ve got a somewhat useful DSL for writing HTML, and pretty printing it.</p>

<p>The main type behind the package is:</p>

<p><pre><span class='hs-keyword'>data</span> <span class='hs-conid'>HTML</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Doctype</span> <span class='hs-conid'>String</span> <span class='hs-conid'>String</span> <span class='hs-conid'>String</span> <span class='hs-keyglyph'>[</span><span class='hs-conid'>HTML</span> <span class='hs-varid'>a</span><span class='hs-keyglyph'>]</span>
            <span class='hs-keyglyph'>|</span> <span class='hs-conid'>Content</span> <span class='hs-varid'>a</span>
            <span class='hs-keyglyph'>|</span> <span class='hs-conid'>Text</span> <span class='hs-conid'>String</span>
            <span class='hs-keyglyph'>|</span> <span class='hs-conid'>Node</span> <span class='hs-conid'>Tag</span> <span class='hs-conid'>Attrs</span> <span class='hs-keyglyph'>[</span><span class='hs-conid'>HTML</span> <span class='hs-varid'>a</span><span class='hs-keyglyph'>]</span>
            <span class='hs-keyglyph'>|</span> <span class='hs-conid'>NoContent</span> <span class='hs-conid'>Tag</span> <span class='hs-conid'>Attrs</span>
            <span class='hs-keyglyph'>|</span> <span class='hs-conid'>Comment</span> <span class='hs-conid'>String</span>
            <span class='hs-keyword'>deriving</span> <span class='hs-conid'>Show</span></pre></p>

<p>where</p>

<p><pre><span class='hs-keyword'>type</span> <span class='hs-conid'>Attr</span> <span class='hs-keyglyph'>=</span> <span class='hs-layout'>(</span><span class='hs-conid'>String</span><span class='hs-layout'>,</span> <span class='hs-conid'>String</span><span class='hs-layout'>)</span>
<span class='hs-keyword'>type</span> <span class='hs-conid'>Attrs</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyglyph'>[</span><span class='hs-conid'>Attr</span><span class='hs-keyglyph'>]</span>
<span class='hs-keyword'>data</span> <span class='hs-conid'>Tag</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Html</span>
         <span class='hs-keyglyph'>|</span> <span class='hs-conid'>ARef</span>
         <span class='hs-keyglyph'>|</span> <span class='hs-conid'>BlockQuote</span>
         <span class='hs-keyglyph'>|</span> <span class='hs-conid'>Body</span>
         ...
         <span class='hs-keyglyph'>|</span> <span class='hs-conid'>Title</span>
         <span class='hs-keyglyph'>|</span> <span class='hs-conid'>TR</span>
         <span class='hs-keyglyph'>|</span> <span class='hs-conid'>UL</span></pre></p>

<p>I&#8217;ve also provided helper functions to make this an actual DSL (I guess?):
<code>
<pre><span class='hs-definition'>example</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>HTML</span> <span class='hs-conid'>()</span>
<span class='hs-definition'>example</span> <span class='hs-keyglyph'>=</span> 
    <span class='hs-varid'>doctype</span> <span class='hs-str'>"html PUBLIC"</span> <span class='hs-str'>"-//W3C//DTD XHTML 1.0 Transitional//EN"</span> <span class='hs-str'>"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"</span> <span class='hs-keyglyph'>[</span>
        <span class='hs-varid'>xhtml</span> <span class='hs-keyglyph'>[</span>
            <span class='hs-varid'>header</span> <span class='hs-keyglyph'>[</span>
                <span class='hs-varid'>title</span> <span class='hs-str'>"My random page"</span><span class='hs-layout'>,</span>
                <span class='hs-varid'>meta</span> <span class='hs-str'>"name"</span> <span class='hs-str'>"Alex"</span>
            <span class='hs-keyglyph'>]</span><span class='hs-layout'>,</span>
            <span class='hs-varid'>body</span> <span class='hs-keyglyph'>[</span>
                <span class='hs-varid'>comment</span> <span class='hs-str'>"This is a comment"</span><span class='hs-layout'>,</span>
                <span class='hs-varid'>para</span> <span class='hs-keyglyph'>[</span>
                    <span class='hs-varid'>text</span> <span class='hs-str'>"The hr tag defines a horizontal rule:"</span>
                <span class='hs-keyglyph'>]</span><span class='hs-layout'>,</span>
                <span class='hs-varid'>hr</span><span class='hs-layout'>,</span>
                <span class='hs-varid'>para</span> <span class='hs-keyglyph'>[</span>
                    <span class='hs-varid'>text</span> <span class='hs-str'>"This is a paragraph"</span>
                <span class='hs-keyglyph'>]</span><span class='hs-layout'>,</span>
                <span class='hs-varid'>hr</span><span class='hs-layout'>,</span>
                <span class='hs-varid'>para</span> <span class='hs-keyglyph'>[</span>
                    <span class='hs-varid'>text</span> <span class='hs-str'>"This is a paragraph"</span>
                <span class='hs-keyglyph'>]</span><span class='hs-layout'>,</span>
                <span class='hs-varid'>table</span> <span class='hs-keyglyph'>[</span>
                    <span class='hs-varid'>tr</span> <span class='hs-keyglyph'>[</span>
                        <span class='hs-varid'>td</span> <span class='hs-keyglyph'>[</span>
                            <span class='hs-varid'>text</span> <span class='hs-str'>"data"</span>
                        <span class='hs-keyglyph'>]</span><span class='hs-layout'>,</span>
                        <span class='hs-varid'>td</span> <span class='hs-keyglyph'>[</span>
                            <span class='hs-varid'>text</span> <span class='hs-str'>"more data"</span>
                        <span class='hs-keyglyph'>]</span>
                    <span class='hs-keyglyph'>]</span><span class='hs-layout'>,</span>
                    <span class='hs-varid'>tr</span> <span class='hs-keyglyph'>[</span>
                        <span class='hs-varid'>td</span> <span class='hs-keyglyph'>[</span>
                            <span class='hs-varid'>text</span> <span class='hs-str'>"more data"</span>
                        <span class='hs-keyglyph'>]</span>
                    <span class='hs-keyglyph'>]</span>
                <span class='hs-keyglyph'>]</span>
            <span class='hs-keyglyph'>]</span>
        <span class='hs-keyglyph'>]</span>
    <span class='hs-keyglyph'>]</span></pre>
</code></p>

<p>produces:</p>

<p><pre><span class='hs-varop'>&lt;!</span><span class='hs-conid'>DOCTYPE</span> <span class='hs-varid'>html</span> <span class='hs-conid'>PUBLIC</span> <span class='hs-str'>"-//W3C//DTD XHTML 1.0 Transitional//EN"</span> <span class='hs-str'>"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"</span><span class='hs-varop'>&gt;</span>
<span class='hs-varop'>&lt;</span><span class='hs-varid'>html</span> <span class='hs-varid'>xmlns</span><span class='hs-keyglyph'>=</span><span class='hs-str'>"http://www.w3.org/1999/xhtml"</span> <span class='hs-varid'>xml</span><span class='hs-conop'>:</span><span class='hs-varid'>lang</span><span class='hs-keyglyph'>=</span><span class='hs-str'>"en"</span> <span class='hs-varid'>lang</span><span class='hs-keyglyph'>=</span><span class='hs-str'>"en"</span><span class='hs-varop'>&gt;</span>
    <span class='hs-varop'>&lt;</span><span class='hs-varid'>head</span> <span class='hs-varop'>&gt;</span>
        <span class='hs-varop'>&lt;</span><span class='hs-varid'>title</span> <span class='hs-varop'>&gt;</span>
            <span class='hs-conid'>My</span> <span class='hs-varid'>random</span> <span class='hs-varid'>page</span>
        <span class='hs-varop'>&lt;/</span><span class='hs-varid'>title</span><span class='hs-varop'>&gt;</span>
        <span class='hs-varop'>&lt;</span><span class='hs-varid'>meta</span> <span class='hs-varid'>name</span><span class='hs-keyglyph'>=</span><span class='hs-str'>"name"</span> <span class='hs-varid'>content</span><span class='hs-keyglyph'>=</span><span class='hs-str'>"Alex"</span><span class='hs-varop'>/&gt;</span>
    <span class='hs-varop'>&lt;/</span><span class='hs-varid'>head</span><span class='hs-varop'>&gt;</span>
    <span class='hs-varop'>&lt;</span><span class='hs-varid'>body</span> <span class='hs-varop'>&gt;</span>
        <span class='hs-varop'>&lt;!--</span> <span class='hs-conid'>This</span> <span class='hs-varid'>is</span> <span class='hs-varid'>a</span> <span class='hs-varid'>comment</span> <span class='hs-varop'>--&gt;</span>
        <span class='hs-varop'>&lt;</span><span class='hs-varid'>p</span> <span class='hs-varop'>&gt;</span>
            <span class='hs-conid'>The</span> <span class='hs-varid'>hr</span> <span class='hs-varid'>tag</span> <span class='hs-varid'>defines</span> <span class='hs-varid'>a</span> <span class='hs-varid'>horizontal</span> <span class='hs-varid'>rule</span><span class='hs-conop'>:</span>
        <span class='hs-varop'>&lt;/</span><span class='hs-varid'>p</span><span class='hs-varop'>&gt;</span>
        <span class='hs-varop'>&lt;</span><span class='hs-varid'>hr</span> <span class='hs-varop'>/&gt;</span>
        <span class='hs-varop'>&lt;</span><span class='hs-varid'>p</span> <span class='hs-varop'>&gt;</span>
            <span class='hs-conid'>This</span> <span class='hs-varid'>is</span> <span class='hs-varid'>a</span> <span class='hs-varid'>paragraph</span>
        <span class='hs-varop'>&lt;/</span><span class='hs-varid'>p</span><span class='hs-varop'>&gt;</span>
        <span class='hs-varop'>&lt;</span><span class='hs-varid'>hr</span> <span class='hs-varop'>/&gt;</span>
        <span class='hs-varop'>&lt;</span><span class='hs-varid'>p</span> <span class='hs-varop'>&gt;</span>
            <span class='hs-conid'>This</span> <span class='hs-varid'>is</span> <span class='hs-varid'>a</span> <span class='hs-varid'>paragraph</span>
        <span class='hs-varop'>&lt;/</span><span class='hs-varid'>p</span><span class='hs-varop'>&gt;</span>
        <span class='hs-varop'>&lt;</span><span class='hs-varid'>table</span> <span class='hs-varop'>&gt;</span>
            <span class='hs-varop'>&lt;</span><span class='hs-varid'>tr</span> <span class='hs-varop'>&gt;</span>
                <span class='hs-varop'>&lt;</span><span class='hs-varid'>td</span> <span class='hs-varop'>&gt;</span>
                    <span class='hs-keyword'>data</span>
                <span class='hs-varop'>&lt;/</span><span class='hs-varid'>td</span><span class='hs-varop'>&gt;</span>
                <span class='hs-varop'>&lt;</span><span class='hs-varid'>td</span> <span class='hs-varop'>&gt;</span>
                    <span class='hs-varid'>more</span> <span class='hs-keyword'>data</span>
                <span class='hs-varop'>&lt;/</span><span class='hs-varid'>td</span><span class='hs-varop'>&gt;</span>
            <span class='hs-varop'>&lt;/</span><span class='hs-varid'>tr</span><span class='hs-varop'>&gt;</span>
            <span class='hs-varop'>&lt;</span><span class='hs-varid'>tr</span> <span class='hs-varop'>&gt;</span>
                <span class='hs-varop'>&lt;</span><span class='hs-varid'>td</span> <span class='hs-varop'>&gt;</span>
                    <span class='hs-varid'>more</span> <span class='hs-keyword'>data</span>
                <span class='hs-varop'>&lt;/</span><span class='hs-varid'>td</span><span class='hs-varop'>&gt;</span>
            <span class='hs-varop'>&lt;/</span><span class='hs-varid'>tr</span><span class='hs-varop'>&gt;</span>
        <span class='hs-varop'>&lt;/</span><span class='hs-varid'>table</span><span class='hs-varop'>&gt;</span>
    <span class='hs-varop'>&lt;/</span><span class='hs-varid'>body</span><span class='hs-varop'>&gt;</span>
<span class='hs-varop'>&lt;/</span><span class='hs-varid'>html</span><span class='hs-varop'>&gt;</span></pre></p>

<p>I don&#8217;t claim that anyone should use this (there&#8217;s a good chance I won&#8217;t be releasing it, unless someone really wants me to), but I&#8217;m still quite proud of it.</p>
