<?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>LAMBDAPHONE &#187; IO</title>
	<atom:link href="http://coder.bsimmons.name/blog/tag/io/feed/" rel="self" type="application/rss+xml" />
	<link>http://coder.bsimmons.name/blog</link>
	<description>fragmentary ideas  ䷿  intellectual what-nots  ䷷  and haskell programming  ䷴</description>
	<lastBuildDate>Tue, 27 Jul 2010 16:58:03 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Some Haskell Boilerplate For Google CodeJam</title>
		<link>http://coder.bsimmons.name/blog/2009/08/haskell-boilerplate-for-google-codejam/</link>
		<comments>http://coder.bsimmons.name/blog/2009/08/haskell-boilerplate-for-google-codejam/#comments</comments>
		<pubDate>Sat, 22 Aug 2009 07:37:16 +0000</pubDate>
		<dc:creator>jberryman</dc:creator>
				<category><![CDATA[haskell]]></category>
		<category><![CDATA[algorithm]]></category>
		<category><![CDATA[CodeJam]]></category>
		<category><![CDATA[IO]]></category>
		<category><![CDATA[parsing]]></category>
		<category><![CDATA[release]]></category>

		<guid isPermaLink="false">http://coder.bsimmons.name/blog/?p=207</guid>
		<description><![CDATA[<p>I put together a skeleton module which should be usable for any of the problems in this year&#8217;s <a href="http://code.google.com/codejam/">Google CodeJam Programming Contest</a> (as long as they don&#8217;t adopt a new format/pattern for the problems this year). The module includes&#8230; <a href="http://coder.bsimmons.name/blog/2009/08/haskell-boilerplate-for-google-codejam/" class="read_more">   [ R E A D &#124; M O R E ]</a></p>]]></description>
			<content:encoded><![CDATA[<p>I put together a skeleton module which should be usable for any of the problems in this year&#8217;s <a href="http://code.google.com/codejam/">Google CodeJam Programming Contest</a> (as long as they don&#8217;t adopt a new format/pattern for the problems this year). The module includes some useful parsing functions which should in the worst case be useful as a cheatsheet for those not too experienced with <a href="http://legacy.cs.uu.nl/daan/download/parsec/parsec.html">Parsec</a> (*cough me). I hope it will encourage people to <a href="http://code.google.com/codejam/contest/registration">sign up</a> and use Haskell in the contest!</p>
<p>To adapt the module to a problem, one defines the following:</p>
<ol>
<li>a type <code>Case</code> into which we will parse a test case (i.e. problem)</li>
<li>a type <code>SolvedCase</code>, representing a solution to a test case</li>
<li>our <code>algorithm :: Case -> SolvedCase</code></li>
<li>a Parser <code>caseParser</code> which can parse a <em>single test case</em> (n.b. not the whole file) into the <code>Case</code> type</li>
<li>a function <code>formatCase :: SolvedCase -> String</code> which brings the solution to the state where it can be prepended with the standard &#8220;Case #1: &#8221; string</li>
</ol>
<p>Here is the module, filled in to solve the Minimum Scalar Product practice problem. You can download the code <a href="http://coder.bsimmons.name/code/Boiler.hs">here</a>:</p>
<p><blockquote class="vimblock"><br>
<span class="Type">module</span>&nbsp;Main<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Type">where</span><br>
<br>
<span class="PreProc">import</span>&nbsp;Text.ParserCombinators.Parsec<br>
<span class="PreProc">import</span>&nbsp;IO <span class="PreProc">hiding</span>&nbsp;(try)<br>
<span class="PreProc">import</span>&nbsp;System.Environment<br>
<br>
<span class="Comment">-- PROBLEM-SPECIFIC IMPORTS --</span><br>
<span class="PreProc">import</span>&nbsp;Data.List (sort)<br>
<span class="PreProc">import</span>&nbsp;Control.Arrow<br>
<span class="Comment">------------------------------</span><br>
<br>
<br>
<span class="Comment">-- the input file will be parsed into a list of some type representing</span><br>
<span class="Comment">-- individual cases to be solved by our algorithm:</span><br>
<span class="Type">type</span>&nbsp;Input&nbsp;<span class="Statement">=</span>&nbsp;[Case]&nbsp;<br>
<br>
<span class="Comment">-- our algorithms will produce a list of some type SolutionCase:</span><br>
<span class="Type">type</span>&nbsp;Solution&nbsp;<span class="Statement">=</span>&nbsp;[SolvedCase]&nbsp;<br>
<br>
<span class="Comment">-- we convert each solved case into a String, which is zipped with</span><br>
<span class="Comment">--&nbsp;&nbsp;the standard &quot;Case #x: &quot; strings for the final output</span><br>
<span class="Type">type</span>&nbsp;Output&nbsp;<span class="Statement">=</span>&nbsp;[<span class="Type">String</span>]<br>
<br>
<br>
<br>
<br>
<br>
<span class="Comment">-- --------------- BEGIN EDITING --------------- --</span><br>
<br>
<br>
<br>
<span class="Comment">-- DEFINE A TYPE TO REPRESENT A SINGLE UNSOLVED TEST CASE: --</span><br>
<span class="Type">type</span>&nbsp;Case&nbsp;<span class="Statement">=</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Comment">-- EXAMPLE: a pair of lists of Ints (our &quot;vectors&quot;):</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;([<span class="Type">Int</span>],[<span class="Type">Int</span>])<br>
<br>
<br>
<span class="Comment">-- DEFINE A TYPE TO REPRESENT A SINGLE SOLVED TEST CASE: --</span><br>
<span class="Type">type</span>&nbsp;SolvedCase&nbsp;<span class="Statement">=</span>&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Comment">-- EXAMPLE: our Minimum Scalar Product as an Int:</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Type">Int</span><br>
<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp; <span class="Comment">-- -- -- ALGORITHMS -- -- --</span><br>
<br>
<br>
<span class="Comment">-- SOLVE A TEST CASE HERE:</span><br>
algorithm&nbsp;<span class="Statement">::</span>&nbsp;Case&nbsp;<span class="Statement">-&gt;</span>&nbsp;SolvedCase<br>
algorithm&nbsp;<span class="Statement">=</span>&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Comment">-- EXAMPLE: simply sort both lists, reverse one, and combine:</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Identifier">sum</span>&nbsp;<span class="Statement">.</span>&nbsp;<span class="Identifier">uncurry</span>&nbsp;(<span class="Identifier">zipWith</span>&nbsp;(<span class="Statement">*</span>))&nbsp;<span class="Statement">.</span>&nbsp;(<span class="Identifier">reverse</span>&nbsp;<span class="Statement">.</span>&nbsp;sort&nbsp;<span class="Statement">***</span>&nbsp;sort)<br>
<br>
<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Comment">-- -- -- PARSING INPUT -- -- --</span><br>
<br>
<br>
<span class="Comment">-- DEFINE PARSER FOR A TEST CASE: --</span><br>
caseParser&nbsp;<span class="Statement">::</span>&nbsp;Parser&nbsp;Case<br>
caseParser&nbsp;<span class="Statement">=</span>&nbsp;<span class="Statement">do</span><br>
&nbsp;&nbsp;&nbsp;&nbsp; <span class="Comment">-- EXAMPLE: parses a case consisting of 3 lines: the first describes the </span><br>
&nbsp;&nbsp;&nbsp;&nbsp; <span class="Comment">--&nbsp;&nbsp;number n of elements in the following two lines, the next two lines </span><br>
&nbsp;&nbsp;&nbsp;&nbsp; <span class="Comment">-- have n space-separated elements:</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;w&nbsp;<span class="Statement">&lt;-</span>&nbsp;word<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Statement">let</span>&nbsp;n&nbsp;<span class="Statement">=</span>&nbsp;<span class="Identifier">read</span>&nbsp;w<br>
&nbsp;&nbsp;&nbsp;&nbsp;as&nbsp;<span class="Statement">&lt;-</span>&nbsp;count&nbsp;n&nbsp;word<br>
&nbsp;&nbsp;&nbsp;&nbsp;bs&nbsp;<span class="Statement">&lt;-</span>&nbsp;count&nbsp;n&nbsp;word<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Identifier">return</span>&nbsp;&nbsp;(<span class="Identifier">map</span>&nbsp;<span class="Identifier">read</span>&nbsp;as,&nbsp;<span class="Identifier">map</span>&nbsp;<span class="Identifier">read</span>&nbsp;bs)<br>
<br>
<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp; <span class="Comment">-- -- -- FORMAT OUTPUT -- -- --</span><br>
<br>
<br>
<span class="Comment">-- DEFINE A FUNCTION FROM AN INDIVIDUAL SolvedCase -&gt; String. </span><br>
formatCase&nbsp;<span class="Statement">::</span>&nbsp;SolvedCase&nbsp;<span class="Statement">-&gt;</span>&nbsp;<span class="Type">String</span><br>
formatCase&nbsp;sol&nbsp;<span class="Statement">=</span>&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Comment">-- EXAMPLE: nothing to speak of here:</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Identifier">show</span>&nbsp;sol<br>
&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp; <br>
<br>
<span class="Comment">-- --------------- STOP EDITING --------------- --</span><br>
<br>
<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Comment">--------------------</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Comment">-- IO BOILERPLATE --</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Comment">--------------------</span><br>
<br>
<br>
main&nbsp;<span class="Statement">=</span>&nbsp;<span class="Statement">do</span><br>
&nbsp;&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp; <span class="Comment">-- pass the input file name to our program:</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;(f<span class="Statement">:</span>_)&nbsp;<span class="Statement">&lt;-</span>&nbsp;getArgs<br>
&nbsp;&nbsp;&nbsp;&nbsp;file&nbsp;&nbsp;<span class="Statement">&lt;-</span>&nbsp;<span class="Identifier">readFile</span>&nbsp;f<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp; <span class="Comment">-- start parsing, solve problem, and prepare output: </span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Statement">let</span>&nbsp;inp&nbsp;&nbsp;<span class="Statement">=</span>&nbsp;parseWith&nbsp;mainParser&nbsp;file<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;solution&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="Statement">=</span>&nbsp;<span class="Identifier">map</span>&nbsp;algorithm&nbsp;inp<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;solutionStrings&nbsp;<span class="Statement">=</span>&nbsp;<span class="Identifier">map</span>&nbsp;formatCase&nbsp;solution<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;outp&nbsp;<span class="Statement">=</span>&nbsp;<span class="Identifier">zipWith</span>&nbsp;(<span class="Statement">++</span>)&nbsp;prefixes&nbsp;solutionStrings<br>
&nbsp;&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp; <span class="Comment">-- write the prepared output to screen:</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Identifier">putStr</span>&nbsp;<span class="Statement">$</span>&nbsp;<span class="Identifier">unlines</span>&nbsp;outp<br>
<br>
<br>
<span class="Comment">-- dies with error, or returns some datatype with our parsed data:</span><br>
parseWith&nbsp;p&nbsp;<span class="Statement">=</span>&nbsp;<span class="Identifier">either</span>&nbsp;(<span class="Identifier">error</span>&nbsp;<span class="Statement">.</span>&nbsp;<span class="Identifier">show</span>)&nbsp;<span class="Identifier">id</span>&nbsp;<span class="Statement">.</span>&nbsp;parse&nbsp;p&nbsp;<span class="Constant">&quot;&quot;</span>&nbsp;<br>
<br>
<span class="Comment">-- to begin parsing, we read in a line containing the number of test cases </span><br>
<span class="Comment">-- to follow. We parse them with caseParser, returning a list:</span><br>
mainParser&nbsp;<span class="Statement">::</span>&nbsp;Parser&nbsp;Input<br>
mainParser&nbsp;<span class="Statement">=</span>&nbsp;<span class="Statement">do</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;n&nbsp;&nbsp;<span class="Statement">&lt;-</span>&nbsp;word<br>
&nbsp;&nbsp;&nbsp;&nbsp;ms&nbsp;<span class="Statement">&lt;-</span>&nbsp;count&nbsp;(<span class="Identifier">read</span>&nbsp;n)&nbsp;caseParser&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Identifier">return</span>&nbsp;ms<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Statement">&lt;?&gt;</span>&nbsp;<span class="Constant">&quot;mainParser&quot;</span><br>
<br>
<span class="Comment">-- strings to prepend to output:</span><br>
prefixes&nbsp;<span class="Statement">=</span>&nbsp;[&nbsp;<span class="Constant">&quot;Case #&quot;</span>&nbsp;<span class="Statement">++</span>&nbsp;<span class="Identifier">show</span>&nbsp;n&nbsp;<span class="Statement">++</span>&nbsp;<span class="Constant">&quot;: &quot;</span>&nbsp;<span class="Statement">|</span>&nbsp;n&nbsp;<span class="Statement">&lt;-</span>&nbsp;[<span class="Constant">1</span><span class="Statement">..</span>]]<br>
<br>
<br>
<br>
<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Comment">---------------------</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Comment">-- VARIOUS PARSERS --</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Comment">---------------------</span><br>
<br>
<br>
<span class="Comment">-- -- LINE PARSERS -- --</span><br>
<br>
<br>
<span class="Comment">-- a single line String, up to the newline:</span><br>
wholeLine&nbsp;<span class="Statement">::</span>&nbsp;Parser&nbsp;<span class="Type">String</span><br>
wholeLine&nbsp;<span class="Statement">=</span>&nbsp;manyTill&nbsp;anyChar&nbsp;(try&nbsp;newline)&nbsp;<span class="Statement">&lt;?&gt;</span>&nbsp;<span class="Constant">&quot;wholeLine&quot;</span><br>
<br>
<span class="Comment">-- parse a String with whitespace-separated values into [String]</span><br>
whiteSepLine&nbsp;<span class="Statement">=</span>&nbsp;manyTill&nbsp;spaceSepWord&nbsp;newline&nbsp;<span class="Statement">&lt;?&gt;</span>&nbsp;<span class="Constant">&quot;whiteSepLine&quot;</span><br>
<br>
<br>
<span class="Comment">-- -- WORD PARSERS -- -- </span><br>
<br>
<br>
<span class="Comment">-- a single word followed by whitespace (space, newline, etc.):</span><br>
word&nbsp;<span class="Statement">=</span>&nbsp;<span class="Statement">do</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;w&nbsp;<span class="Statement">&lt;-</span>&nbsp;many1&nbsp;nonWhite<br>
&nbsp;&nbsp;&nbsp;&nbsp;spaces<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Identifier">return</span>&nbsp;w<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Statement">&lt;?&gt;</span>&nbsp;<span class="Constant">&quot;word&quot;</span><br>
<br>
<span class="Comment">-- a single word followed by one or more ' ' characters (won't consume '\n')</span><br>
spaceSepWord&nbsp;<span class="Statement">=</span>&nbsp;<span class="Statement">do</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;w&nbsp;<span class="Statement">&lt;-</span>&nbsp;many1&nbsp;nonWhite<br>
&nbsp;&nbsp;&nbsp;&nbsp;many&nbsp;(char&nbsp;<span class="Constant">' '</span>)<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Identifier">return</span>&nbsp;w<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Statement">&lt;?&gt;</span>&nbsp;<span class="Constant">&quot;spaceSepWord&quot;</span><br>
<br>
<span class="Comment">-- e.g. &quot;hello:world&quot; ---&gt; (&quot;hello&quot;,&quot;world&quot;)</span><br>
<span class="Comment">-- won't consume newlines</span><br>
twoWordsSepBy&nbsp;c&nbsp;<span class="Statement">=</span>&nbsp;<span class="Statement">do</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;<span class="Statement">&lt;-</span>&nbsp;manyTill&nbsp;nonWhite&nbsp;(try<span class="Statement">$</span>&nbsp;char&nbsp;c)<br>
&nbsp;&nbsp;&nbsp;&nbsp;y&nbsp;<span class="Statement">&lt;-</span>&nbsp;many1&nbsp;nonWhite<br>
&nbsp;&nbsp;&nbsp;&nbsp;many&nbsp;(char&nbsp;<span class="Constant">' '</span>)<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Identifier">return</span>&nbsp;(x,y)<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="Statement">&lt;?&gt;</span>&nbsp;<span class="Constant">&quot;twoWordsSepBy&quot;</span><br>
<br>
<br>
<span class="Comment">-- -- CHARACTER PARSERS -- --</span><br>
<br>
<br>
<span class="Comment">-- nonWhitespace character:</span><br>
nonWhite&nbsp;<span class="Statement">=</span>&nbsp;noneOf&nbsp;<span class="Constant">&quot; </span><span class="Special">\v\f\t\r\n</span><span class="Constant">&quot;</span>&nbsp;<span class="Statement">&lt;?&gt;</span>&nbsp;<span class="Constant">&quot;nonWhite&quot;</span><br>
<br>
<br>
<br></blockquote></p>
]]></content:encoded>
			<wfw:commentRss>http://coder.bsimmons.name/blog/2009/08/haskell-boilerplate-for-google-codejam/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>directory-tree module released</title>
		<link>http://coder.bsimmons.name/blog/2009/05/directory-tree-module-released/</link>
		<comments>http://coder.bsimmons.name/blog/2009/05/directory-tree-module-released/#comments</comments>
		<pubDate>Sat, 09 May 2009 16:33:12 +0000</pubDate>
		<dc:creator>jberryman</dc:creator>
				<category><![CDATA[haskell]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[hackage]]></category>
		<category><![CDATA[IO]]></category>
		<category><![CDATA[library]]></category>
		<category><![CDATA[release]]></category>
		<category><![CDATA[Tree]]></category>

		<guid isPermaLink="false">http://coder.bsimmons.name/blog/?p=148</guid>
		<description><![CDATA[<p>I&#8217;ve released my first package, <a href="http://hackage.haskell.org/cgi-bin/hackage-scripts/package/directory-tree">up now on hackage</a> (haddock docs should be generated soon). The module provides a simple data structure that mirrors a directory tree, and some useful functions for doing IO on directories of files. You&#8230; <a href="http://coder.bsimmons.name/blog/2009/05/directory-tree-module-released/" class="read_more">   [ R E A D &#124; M O R E ]</a></p>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve released my first package, <a href="http://hackage.haskell.org/cgi-bin/hackage-scripts/package/directory-tree">up now on hackage</a> (haddock docs should be generated soon). The module provides a simple data structure that mirrors a directory tree, and some useful functions for doing IO on directories of files. You can <a href="http://coder.bsimmons.name/blog/2009/04/a-directorytree-module-and-some-examples/">read more about it here</a>.</p>
<p>It&#8217;s very likely there are some bugs, especially related to cross platform issues with file names and paths. The module is also fairly bare, so please send me any requests for functionality that I haven&#8217;t thought of, as well as any bugs you might find. </p>
<p>You can install it with:</p>
<blockquote><p>$ cabal install directory-tree</p></blockquote>
<p>And get the source with:</p>
<blockquote><p>$ darcs get http://coder.bsimmons.name/code/DirectoryTree/</p></blockquote>
<p>I hope this is useful to someone!</p>
]]></content:encoded>
			<wfw:commentRss>http://coder.bsimmons.name/blog/2009/05/directory-tree-module-released/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>a DirectoryTree module and some examples</title>
		<link>http://coder.bsimmons.name/blog/2009/04/a-directorytree-module-and-some-examples/</link>
		<comments>http://coder.bsimmons.name/blog/2009/04/a-directorytree-module-and-some-examples/#comments</comments>
		<pubDate>Thu, 30 Apr 2009 03:47:10 +0000</pubDate>
		<dc:creator>jberryman</dc:creator>
				<category><![CDATA[haskell]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[IO]]></category>
		<category><![CDATA[library]]></category>
		<category><![CDATA[Tree]]></category>

		<guid isPermaLink="false">http://coder.bsimmons.name/blog/?p=140</guid>
		<description><![CDATA[<p>UPDATE: <em>I&#8217;ve just released this as my first package on hackage. You can read more and write any comments <a href="http://coder.bsimmons.name/blog/2009/05/directory-tree-module-released/">here</a>.</em></p>
<p>I just put together a library that provides a simple tree data structure to represent the structure of files&#8230; <a href="http://coder.bsimmons.name/blog/2009/04/a-directorytree-module-and-some-examples/" class="read_more">   [ R E A D &#124; M O R E ]</a></p>]]></description>
			<content:encoded><![CDATA[<p>UPDATE: <em>I&#8217;ve just released this as my first package on hackage. You can read more and write any comments <a href="http://coder.bsimmons.name/blog/2009/05/directory-tree-module-released/">here</a>.</em></p>
<p>I just put together a library that provides a simple tree data structure to represent the structure of files and directories in the OS. It provides some simple IO functions like <code>readDirectory</code> (analogous to <code>readFile</code>) which &#8220;opens&#8221; a directory, returning a DirTree of Strings in the IO monad. </p>
<p>The nice thing is that by defining a simple instance for <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Data-Traversable.html">Traversable</a> (and the default instances for Foldable and Functor that we get for free) we get a whole array of nice functions which we can apply to directory structures! For example, we can combine all the text in a directory of files with:</p>
<p><blockquote class="vimblock"><br>
combineFiles&nbsp;<span class="Statement">::</span>&nbsp;<span class="Type">FilePath</span>&nbsp;<span class="Statement">-&gt;</span>&nbsp;<span class="Type">IO</span>&nbsp;[<span class="Type">Char</span>]<br>
combineFiles&nbsp;d&nbsp;<span class="Statement">=</span>&nbsp;<span class="Statement">do</span>&nbsp;(_&nbsp;<span class="Statement">:/</span>&nbsp;t)&nbsp;<span class="Statement">&lt;-</span>&nbsp;readDirectory&nbsp;d<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="Identifier">return</span>&nbsp;<span class="Statement">$</span>&nbsp;F.foldr1&nbsp;(<span class="Statement">++</span>)&nbsp;t<br>
<br></blockquote></p>
<p>(the <code>(_:/t)</code> portion ignores the base directory returned). The <code>DirTree</code> type also includes a constructor for handling failures. Here is the type definition:</p>
<p><blockquote class="vimblock"><br>
<span class="Type">data</span>&nbsp;DirTree&nbsp;a&nbsp;<span class="Statement">=</span>&nbsp;Dir&nbsp;{&nbsp;name&nbsp;&nbsp;&nbsp;&nbsp; <span class="Statement">::</span>&nbsp;FileName,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; contents&nbsp;<span class="Statement">::</span>&nbsp;[DirTree&nbsp;a]&nbsp;&nbsp;}&nbsp;<span class="Comment">--files + directories</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="Statement">|</span>&nbsp;File&nbsp;{&nbsp;name&nbsp;<span class="Statement">::</span>&nbsp;FileName,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;file&nbsp;<span class="Statement">::</span>&nbsp;a&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="Statement">|</span>&nbsp;Failed&nbsp;{&nbsp;name&nbsp;<span class="Statement">::</span>&nbsp;FileName,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;err&nbsp;&nbsp;<span class="Statement">::</span>&nbsp;Exception&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="Type">deriving</span>&nbsp;(<span class="Type">Show</span>,&nbsp;<span class="Type">Eq</span>)<br>
<br></blockquote></p>
<p>I have created a <a href="http://coder.bsimmons.name/code/DirectoryTree/examples.hs">file with three examples</a>: </p>
<ol>
<li>in the first we simulate the command <code>darcs initialize</code> to illustrate creating a directory of files by hand, and writing it to disk.</li>
<li>second, we show combining several different directories from around the filesystem and assembling the into a new tree structure.</li>
<li>lastly, we use our <code>readDirectoryWith</code> (with Data.ByteString.readFile), and our Foldable instance to hash all the files in a directory structure (with Thomas DuBuisson&#8217;s <a href="http://hackage.haskell.org/cgi-bin/hackage-scripts/package/pureMD5">pureMD5</a> package) and compare it to the hash of a different directory to see if the contents match exactly</li>
</ol>
<p>There are probably bugs, and there are many useful functions I can think of to add if people think this is useful. I would be interested in hearing your thoughts on the interface, on any functionality you would like added, and anything else!</p>
<p>You can get the module and examples.hs with:</p>
<blockquote><p>
$ darcs get http://coder.bsimmons.name/code/DirectoryTree/</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://coder.bsimmons.name/blog/2009/04/a-directorytree-module-and-some-examples/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Why I love Hoogle</title>
		<link>http://coder.bsimmons.name/blog/2009/04/why-i-love-hoogle/</link>
		<comments>http://coder.bsimmons.name/blog/2009/04/why-i-love-hoogle/#comments</comments>
		<pubDate>Sat, 25 Apr 2009 02:42:47 +0000</pubDate>
		<dc:creator>jberryman</dc:creator>
				<category><![CDATA[haskell]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[IO]]></category>
		<category><![CDATA[short]]></category>
		<category><![CDATA[Tree]]></category>

		<guid isPermaLink="false">http://coder.bsimmons.name/blog/?p=135</guid>
		<description><![CDATA[<p>I&#8217;m working on a module called <code>DirectoryTree</code>, a simple tree structure mirroring the structure of a directory tree in the <a href="http://en.wikipedia.org/wiki/Input/output">outside world</a>, with functions to hopefully make it easy to do useful things (I&#8217;m not sure if something like&#8230; <a href="http://coder.bsimmons.name/blog/2009/04/why-i-love-hoogle/" class="read_more">   [ R E A D &#124; M O R E ]</a></p>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m working on a module called <code>DirectoryTree</code>, a simple tree structure mirroring the structure of a directory tree in the <a href="http://en.wikipedia.org/wiki/Input/output">outside world</a>, with functions to hopefully make it easy to do useful things (I&#8217;m not sure if something like this already exists). Here is the data-type:</p>
<p><blockquote class="vimblock"><br>
<span class="Type">data</span>&nbsp;DirTree&nbsp;a&nbsp;<span class="Statement">=</span>&nbsp;Dir&nbsp;{&nbsp;name&nbsp;&nbsp;<span class="Statement">::</span>&nbsp;<span class="Type">String</span>,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; files&nbsp;<span class="Statement">::</span>&nbsp;[a],<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; directories&nbsp;<span class="Statement">::</span>&nbsp;[DirTree&nbsp;a]&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="Statement">|</span>&nbsp;Fail&nbsp;<span class="Type">String</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="Comment">--file/directory name</span><br>
<br></blockquote></p>
<p>I would like to do things like map over a <code>DirTree</code> of <code>FilePath</code>s, returning a tree (in the IO monad) of <code>Handle</code>s&#8230; so the code involves a lot of slogging through the IO monad, which I&#8217;m not totally comfortable with yet.</p>
<p>I&#8217;m feeling out how to proceed with the above and begin to define this function:</p>
<p><blockquote class="vimblock"><br>
<span class="Comment">-- an abstraction for this? monad?:</span><br>
ioMap&nbsp;<span class="Statement">::</span>&nbsp;(a&nbsp;<span class="Statement">-&gt;</span>&nbsp;<span class="Type">IO</span>&nbsp;b)&nbsp;<span class="Statement">-&gt;</span>&nbsp;DirTree&nbsp;a&nbsp;<span class="Statement">-&gt;</span>&nbsp;<span class="Type">IO</span>&nbsp;(DirTree&nbsp;b)<br>
<br></blockquote></p>
<p>&#8230;there&#8217;s something happening here but I don&#8217;t know what it is; let&#8217;s see what <a href="http://haskell.org/hoogle/">Hoogle</a> can tell me about this abstraction. I take the type definition and plug it into firefox&#8217;s hoogle search plugin <a href="http://www.haskell.org/hoogle/?q=(a+-%3E+IO+b)+-%3E+DirTree+a+-%3E+IO+(DirTree+b)&#038;format=sherlock">and voila!</a>; I&#8217;m presented with the following matches:</p>
<blockquote><p>    Data.Traversable:<br />
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)<br />
for :: (Traversable t, Applicative f) => t a -> (a -> f b) -> f (t b)<br />
mapM :: (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b)<br />
forM :: (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b)</p></blockquote>
<p> I see that <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Data-Traversable.html#v:mapM">mapM</a> from <code>Data.Traversable</code> looks like what I want, and <code>traverse</code> also looks useful.</p>
<p>I learned something, and have an idea of how to proceed, and that&#8217;s why I love hoogle :)</p>
]]></content:encoded>
			<wfw:commentRss>http://coder.bsimmons.name/blog/2009/04/why-i-love-hoogle/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
