<?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>Sun, 29 Jan 2012 17:24:54 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Module &#8216;chan-split&#8217; released</title>
		<link>http://coder.bsimmons.name/blog/2011/07/module-chan-split-released/</link>
		<comments>http://coder.bsimmons.name/blog/2011/07/module-chan-split-released/#comments</comments>
		<pubDate>Mon, 18 Jul 2011 02:17:09 +0000</pubDate>
		<dc:creator>jberryman</dc:creator>
				<category><![CDATA[haskell]]></category>
		<category><![CDATA[concurrency]]></category>
		<category><![CDATA[IO]]></category>
		<category><![CDATA[library]]></category>
		<category><![CDATA[release]]></category>

		<guid isPermaLink="false">http://coder.bsimmons.name/blog/?p=571</guid>
		<description><![CDATA[<h2>Whaa?</h2>
<p>chan-split is a haskell library that is a wrapper around <a href="http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Concurrent-Chan.html"><code>Control.Concurrent.Chan</code></a>s that separates a Chan into a readable side and a writable side. </p>
<p>We also provide two other modules: <code>Data.Cofunctor</code> (because there didn&#8217;t seem to be one&#8230; <a href="http://coder.bsimmons.name/blog/2011/07/module-chan-split-released/" class="read_more">   [ R E A D &#124; M O R E ]</a></p>]]></description>
			<content:encoded><![CDATA[<h2>Whaa?</h2>
<p>chan-split is a haskell library that is a wrapper around <a href="http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Concurrent-Chan.html"><code>Control.Concurrent.Chan</code></a>s that separates a Chan into a readable side and a writable side. </p>
<p>We also provide two other modules: <code>Data.Cofunctor</code> (because there didn&#8217;t seem to be one anywhere), and <code>Control.Concurrent.Chan.Class</code>. The latter creates two classes: <code>ReadableChan</code> and <code>WritableChan</code>, making the fundamental chan functions polymorphic, and defining an instance for standard <code>Chan</code> as well as <code>MVar</code> (an MVar is a singleton bounded channel, wanna fight about it?).</p>
<h2>Why?</h2>
<p>Having separate read/write sides makes it easier to reason about your code, supports doing some cool things (defining <code>Functor</code> and <code>Cofunctor</code> instances), and makes more sense (e.g. the function of <a href="http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Concurrent-Chan.html#t:dupChan">dupChan</a> in the base library is much easier to understand as an operation that happens on an <code>OutChan</code>).</p>
<p>Also I use it in (the coming new, less stupid version of) my module <a href="http://hackage.haskell.org/package/simple-actors">simple-actors</a>.</p>
<h2>Where?</h2>
<p>You can get it with a:</p>
<blockquote><p>cabal install chan-split</p></blockquote>
<p>And check out the <a href="http://hackage.haskell.org/package/chan-split">docs on hackage</a>. Or check out the <a href="https://github.com/jberryman/chan-split">source on github</a> and send me pull requests.</p>
<h1>Usage</h1>
<p>Let&#8217;s write the numbers 1 &#8211; 10 to the InChan and read them as a stream in the OutChan:</p>
<p><blockquote class="vimblock"><br />
<span class="lnr">&nbsp;1&nbsp;</span><span class="Structure">module</span>&nbsp;<span class="Normal">Main</span><br />
<span class="lnr">&nbsp;2&nbsp;</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="Structure">where</span><br />
<span class="lnr">&nbsp;3&nbsp;</span><br />
<span class="lnr">&nbsp;4&nbsp;</span><span class="PreProc">import</span>&nbsp;<span class="Normal">Control.Concurrent.Chan.Split</span><br />
<span class="lnr">&nbsp;5&nbsp;</span><span class="PreProc">import</span>&nbsp;<span class="Normal">Control.Concurrent</span>(<span class="Function">forkIO</span>)<br />
<span class="lnr">&nbsp;6&nbsp;</span><br />
<span class="lnr">&nbsp;7&nbsp;</span><span class="Function">main</span>&nbsp;<span class="Operator">=</span>&nbsp;<span class="Statement">do</span><br />
<span class="lnr">&nbsp;8&nbsp;</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="Comment">-- Instead of a single Chan, we initialize a pair of (InChan,OutChan)</span><br />
<span class="lnr">&nbsp;9&nbsp;</span>&nbsp;&nbsp;&nbsp;&nbsp;(inC,outC)&nbsp;<span class="Operator">&lt;-</span>&nbsp;newSplitChan<br />
<span class="lnr">10&nbsp;</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="Comment">-- fork a writer on the InChan</span><br />
<span class="lnr">11&nbsp;</span>&nbsp;&nbsp;&nbsp;&nbsp;forkIO&nbsp;<span class="Operator">$</span>&nbsp;writeStuffTo&nbsp;inC&nbsp;[<span class="Number">1</span><span class="Operator">..</span><span class="Number">10</span>]<br />
<span class="lnr">12&nbsp;</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="Comment">-- read from the OutChan in the main thread:</span><br />
<span class="lnr">13&nbsp;</span>&nbsp;&nbsp;&nbsp;&nbsp;getStuffOutOf&nbsp;outC&nbsp;<span class="Operator">&gt;&gt;=</span><br />
<span class="lnr">14&nbsp;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mapM_&nbsp;print&nbsp;<span class="Operator">.</span>&nbsp;take&nbsp;<span class="Number">10</span>&nbsp;<br />
<br /></blockquote></p>
<p>And we&#8217;ll make <code>writeStuffTo</code> and <code>getStuffOutOf</code>, simply be the standard functions. Note that <code>writeListToChan</code> is actually polymorphic.</p>
<p><blockquote class="vimblock"><br />
<span class="lnr">16&nbsp;</span><span class="Function">writeStuffTo</span>&nbsp;::&nbsp;InChan&nbsp;Int&nbsp;<span class="Operator">-&gt;</span>&nbsp;[Int]&nbsp;<span class="Operator">-&gt;</span>&nbsp;IO&nbsp;()<br />
<span class="lnr">17&nbsp;</span><span class="Function">writeStuffTo</span>&nbsp;<span class="Operator">=</span>&nbsp;writeList2Chan<br />
<span class="lnr">18&nbsp;</span><br />
<span class="lnr">19&nbsp;</span><span class="Function">getStuffOutOf</span>&nbsp;::&nbsp;OutChan&nbsp;Int&nbsp;<span class="Operator">-&gt;</span>&nbsp;IO&nbsp;[Int]<br />
<span class="lnr">20&nbsp;</span><span class="Function">getStuffOutOf</span>&nbsp;<span class="Operator">=</span>&nbsp;getChanContents<br />
<br /></blockquote></p>
<p>Now I&#8217;ll demonstrate the use of our Functor and Cofunctor instances by re-defining those two functions above, after importing our Cofunctor class</p>
<p><blockquote class="vimblock"><br />
<span class="lnr">17&nbsp;</span><span class="PreProc">import</span>&nbsp;<span class="Normal">Data.Cofunctor</span><br />
<span class="lnr">18&nbsp;</span><br />
<span class="lnr">19&nbsp;</span><span class="Operator">...</span><br />
<span class="lnr">20&nbsp;</span><br />
<span class="lnr">21&nbsp;</span><span class="Comment">-- we could convert the [Int] to [String] here but will instead demonstrate the</span><br />
<span class="lnr">22&nbsp;</span><span class="Comment">-- Cofmap instance:</span><br />
<span class="lnr">23&nbsp;</span><span class="Function">writeStuffTo</span>&nbsp;::&nbsp;InChan&nbsp;String&nbsp;<span class="Operator">-&gt;</span>&nbsp;[Int]&nbsp;<span class="Operator">-&gt;</span>&nbsp;IO&nbsp;()<br />
<span class="lnr">24&nbsp;</span><span class="Function">writeStuffTo</span>&nbsp;<span class="Operator">=</span>&nbsp;writeList2Chan&nbsp;<span class="Operator">.</span>&nbsp;cofmap&nbsp;show<br />
<span class="lnr">25&nbsp;</span><br />
<span class="lnr">26&nbsp;</span><span class="Comment">-- likewise this demonstrates the Functor instance of OutChan:</span><br />
<span class="lnr">27&nbsp;</span><span class="Function">getStuffOutOf</span>&nbsp;::&nbsp;OutChan&nbsp;String&nbsp;<span class="Operator">-&gt;</span>&nbsp;IO&nbsp;[Int]<br />
<span class="lnr">28&nbsp;</span><span class="Function">getStuffOutOf</span>&nbsp;<span class="Operator">=</span>&nbsp;getChanContents&nbsp;<span class="Operator">.</span>&nbsp;fmap&nbsp;read<br />
<br /></blockquote></p>
<p>All right, leave your love or hate and stay tuned for the new (less stupider) simple-actors lib.</p>
]]></content:encoded>
			<wfw:commentRss>http://coder.bsimmons.name/blog/2011/07/module-chan-split-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Synchronized Concurrent IO Actions</title>
		<link>http://coder.bsimmons.name/blog/2011/02/synchronized-concurrent-io-actions/</link>
		<comments>http://coder.bsimmons.name/blog/2011/02/synchronized-concurrent-io-actions/#comments</comments>
		<pubDate>Thu, 24 Feb 2011 15:16:09 +0000</pubDate>
		<dc:creator>jberryman</dc:creator>
				<category><![CDATA[haskell]]></category>
		<category><![CDATA[concurrency]]></category>
		<category><![CDATA[IO]]></category>

		<guid isPermaLink="false">http://coder.bsimmons.name/blog/?p=545</guid>
		<description><![CDATA[<blockquote><p>This is a bit of literate haskell code that works through a system for running concurrent IO computations that are synchronized on a stream. So we have many &#8220;nodes&#8221; of the type <code>:: a -> IO ()</code> running concurrently on</p></blockquote><p>&#8230; <a href="http://coder.bsimmons.name/blog/2011/02/synchronized-concurrent-io-actions/" class="read_more">   [ R E A D &#124; M O R E ]</a></p>]]></description>
			<content:encoded><![CDATA[<blockquote><p>This is a bit of literate haskell code that works through a system for running concurrent IO computations that are synchronized on a stream. So we have many &#8220;nodes&#8221; of the type <code>:: a -> IO ()</code> running concurrently on a single stream, where we would like each node to wait until all nodes have processed a stream element before any are allowed to proceed onto the next element.</p>
<p>This was motivated by the desire to simulate a system in which many nodes are interacting independently according to a time-synchronized algorithm. So the &#8220;stream&#8221; the nodes process is time.</p>
<p>I wanted to use real concurrency because it sounded fun. It would of course be possible to <em>simulate</em> a time-synchronized system without using real concurrency. </p></blockquote>
<p><span id="more-545"></span><br />
<div class="vimblock"><br />
<span class="Comment">&gt;</span>&nbsp;module&nbsp;Main<br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="Type">where</span><br />
<span class="Comment">&gt;</span><br />
<span class="Comment">&gt;</span>&nbsp;<span class="PreProc">import</span>&nbsp;<span class="Normal">Control.Concurrent</span><br />
<span class="Comment">&gt;</span>&nbsp;<span class="PreProc">import</span>&nbsp;<span class="Normal">Control.Monad</span><br />
<br />
Demonstrating a system for coordinating independent threads that need to be<br />
synchronized to a stream. For example we might be simulating some nodes that<br />
each act independently performing some action at regular time intervals. In<br />
this case the coordinating stream could be a list of ascending integers<br />
representing time.<br />
<br />
<br />
A node is a function over time. In this case it represents a clock, every<br />
time it prints representing a tick. We want the nodes to be independent but<br />
to simulate a time-snchronized system.<br />
<br />
Here we have a simple example node that does nothing but take an Int and print<br />
it:<br />
<br />
<span class="Comment">&gt;</span>&nbsp;nodeSimple&nbsp;<span class="Statement">::</span>&nbsp;Int&nbsp;<span class="Statement">-&gt;</span>&nbsp;IO&nbsp;()<br />
<span class="Comment">&gt;</span>&nbsp;nodeSimple&nbsp;<span class="Statement">=</span>&nbsp;putStr&nbsp;<span class="Statement">.</span>&nbsp;show<br />
<br />
<br />
the synchronizer takes a list of functions such as the one above, each<br />
representing a different node, and a synchronizing stream of inputs. It then&nbsp;<br />
runs the node functions concurrently and synchronously.<br />
<br />
This is a simple version without worrying about actual concurrency:<br />
<br />
<span class="Comment">&gt;</span>&nbsp;synchronizeSimple&nbsp;<span class="Statement">::</span>&nbsp;[a&nbsp;<span class="Statement">-&gt;</span>&nbsp;IO&nbsp;()]&nbsp;<span class="Statement">-&gt;</span>&nbsp;[a]&nbsp;<span class="Statement">-&gt;</span>&nbsp;IO&nbsp;()<br />
<span class="Comment">&gt;</span>&nbsp;synchronizeSimple&nbsp;fs&nbsp;<span class="Statement">=</span>&nbsp;mapM_&nbsp;(<span class="Statement">\</span>a<span class="Statement">-&gt;</span>&nbsp;mapM_&nbsp;(<span class="Statement">$</span>&nbsp;a)&nbsp;fs)&nbsp;<br />
<br />
Each &quot;node&quot; function executes on a given input before any of the nodes can move<br />
onto the next input. This is the goal. In the concurrent implementation below,<br />
the nodes may execute at any order during a single &quot;step&quot;, but block until all<br />
nodes have executed on the input.<br />
<br />
<span class="Comment">&gt;</span>&nbsp;testSimpleSync&nbsp;<span class="Statement">=</span>&nbsp;synchronizeSimple&nbsp;[nodeSimple,nodeSimple,nodeSimple]&nbsp;[<span class="Constant">1</span><span class="Statement">..</span><span class="Constant">5</span>]<br />
<br />
-------------------------------------------------------------------------------<br />
<br />
Now we want to be able to replicate the above but have the &quot;node&quot; functions be<br />
running in separate, but coordinating threads.&nbsp;<br />
<br />
We will add to this the requirement and constraint that the input stream will be<br />
infinite and each node must indicate when its job is done by returning a Bool at<br />
each step, with False indicating it is no longer taking input:<br />
<br />
<span class="Comment">&gt;</span>&nbsp;<span class="Type">type</span>&nbsp;Node&nbsp;a&nbsp;<span class="Statement">=</span>&nbsp;a&nbsp;<span class="Statement">-&gt;</span>&nbsp;IO&nbsp;Bool<br />
<br />
Here are three such Node types. We expect them to exit at different times<br />
according to their guard predicate:<br />
<br />
<span class="Comment">&gt;</span>&nbsp;nodeA,&nbsp;nodeB,&nbsp;nodeC&nbsp;<span class="Statement">::</span>&nbsp;Node&nbsp;Int<br />
<span class="Comment">&gt;</span>&nbsp;nodeA&nbsp;a&nbsp;<span class="Statement">|</span>&nbsp;a&nbsp;<span class="Statement">&lt;</span>&nbsp;<span class="Constant">50</span>&nbsp;<span class="Statement">=</span>&nbsp;comp&nbsp;a&nbsp;<span class="Statement">`seq`</span>&nbsp;(putStr&nbsp;<span class="Constant">&quot;A&quot;</span>)&nbsp;<span class="Statement">&gt;&gt;</span>&nbsp;return&nbsp;True<br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="Statement">|</span>&nbsp;otherwise&nbsp;<span class="Statement">=</span>&nbsp;return&nbsp;False<br />
<span class="Comment">&gt;</span>&nbsp;nodeB&nbsp;a&nbsp;<span class="Statement">|</span>&nbsp;a&nbsp;<span class="Statement">&lt;</span>&nbsp;<span class="Constant">700</span>&nbsp;<span class="Statement">=</span>&nbsp;comp&nbsp;a&nbsp;<span class="Statement">`seq`</span>&nbsp;(putStr&nbsp;<span class="Constant">&quot;B&quot;</span>)&nbsp;<span class="Statement">&gt;&gt;</span>&nbsp;return&nbsp;True<br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="Statement">|</span>&nbsp;otherwise&nbsp;<span class="Statement">=</span>&nbsp;return&nbsp;False<br />
<span class="Comment">&gt;</span>&nbsp;nodeC&nbsp;a&nbsp;<span class="Statement">|</span>&nbsp;a&nbsp;<span class="Statement">&lt;</span>&nbsp;<span class="Constant">1000</span>&nbsp;<span class="Statement">=</span>&nbsp;comp&nbsp;a&nbsp;<span class="Statement">`seq`</span>&nbsp;(putStr&nbsp;<span class="Constant">&quot;C&quot;</span>)&nbsp;<span class="Statement">&gt;&gt;</span>&nbsp;return&nbsp;True<br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="Statement">|</span>&nbsp;otherwise&nbsp;<span class="Statement">=</span>&nbsp;return&nbsp;False<br />
<span class="Comment">&gt;</span>&nbsp;<br />
<span class="Comment">&gt;</span>&nbsp;<span class="Comment">-- an expensive computation to see if things are actually running concurrently</span><br />
<span class="Comment">&gt;</span>&nbsp;comp&nbsp;a&nbsp;<span class="Statement">=</span>&nbsp;sum&nbsp;[a<span class="Statement">..</span><span class="Constant">10000</span>]<br />
<br />
<br />
<br />
And here a synchronizing function that uses a set of channels to coordinate the<br />
action of the nodes, each of which are now a seperate thread:<br />
<br />
<span class="Comment">&gt;</span>&nbsp;synchronize&nbsp;<span class="Statement">::</span>&nbsp;[Node&nbsp;a]&nbsp;<span class="Statement">-&gt;</span>&nbsp;[a]&nbsp;<span class="Statement">-&gt;</span>&nbsp;IO&nbsp;()<br />
<span class="Comment">&gt;</span>&nbsp;synchronize&nbsp;ns&nbsp;str&nbsp;<span class="Statement">=</span>&nbsp;<span class="Statement">do</span><br />
<span class="Comment">&gt;</span>&nbsp;<span class="Comment">-- knowing the number of nodes just lets the programmer be lazy for now</span><br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="Statement">let</span>&nbsp;n&nbsp;<span class="Statement">=</span>&nbsp;length&nbsp;ns<br />
<span class="Comment">&gt;</span>&nbsp;<br />
<span class="Comment">&gt;</span>&nbsp;<span class="Comment">-- the input stream gets pushed down this pipe, and read from duplicates&nbsp;</span><br />
<span class="Comment">&gt;</span>&nbsp;<span class="Comment">-- of this Chan:</span><br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;broadcastChan&nbsp;<span class="Statement">&lt;-</span>&nbsp;newChan<br />
<span class="Comment">&gt;</span>&nbsp;<br />
<span class="Comment">&gt;</span>&nbsp;<span class="Comment">-- the pipe that all the nodes report back to and the synchronizer listens</span><br />
<span class="Comment">&gt;</span>&nbsp;<span class="Comment">-- to, in order to know when to feed another stream value down the&nbsp;</span><br />
<span class="Comment">&gt;</span>&nbsp;<span class="Comment">-- broadcast pipe:</span><br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;receiverChan&nbsp;<span class="Statement">&lt;-</span>&nbsp;newChan<br />
<span class="Comment">&gt;</span>&nbsp;<br />
<span class="Comment">&gt;</span>&nbsp;<span class="Comment">-- fork off the nodes, which will block until the coordinator starts:</span><br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="Statement">let</span>&nbsp;runNode&nbsp;node&nbsp;<span class="Statement">=</span>&nbsp;<span class="Statement">do</span><br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="Comment">----SQUASHED BUG: forked before duplicating Chan caused Chan to</span><br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="Comment">----be duplicated after first input sent through (I think):</span><br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bChanDup&nbsp;<span class="Statement">&lt;-</span>&nbsp;dupChan&nbsp;broadcastChan<br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;forkIO&nbsp;<span class="Statement">$</span>&nbsp;nodeLoop&nbsp;bChanDup&nbsp;receiverChan&nbsp;node<br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mapM_&nbsp;runNode&nbsp;ns&nbsp;<br />
<span class="Comment">&gt;</span><br />
<span class="Comment">&gt;</span>&nbsp;<span class="Comment">-- Start the computation by running the coordinator which will start by</span><br />
<span class="Comment">&gt;</span>&nbsp;<span class="Comment">-- putting the first value in the broadcast Chan</span><br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;coordinator&nbsp;broadcastChan&nbsp;receiverChan&nbsp;n&nbsp;str<br />
<br />
<br />
This function repeatedly runs a node action on the inputs, reporting each run&nbsp;<br />
back up the receiverChan:<br />
<br />
<span class="Comment">&gt;</span>&nbsp;nodeLoop&nbsp;<span class="Statement">::</span>&nbsp;Chan&nbsp;a&nbsp;<span class="Statement">-&gt;</span>&nbsp;Chan&nbsp;Bool&nbsp;<span class="Statement">-&gt;</span>&nbsp;Node&nbsp;a&nbsp;<span class="Statement">-&gt;</span>&nbsp;IO&nbsp;()<br />
<span class="Comment">&gt;</span>&nbsp;nodeLoop&nbsp;bChan&nbsp;rChan&nbsp;n&nbsp;<span class="Statement">=</span>&nbsp;loop&nbsp;&nbsp;<span class="Type">where</span><br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;loop&nbsp;<span class="Statement">=</span>&nbsp;<span class="Statement">do</span><br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="Comment">-- read the next input (blocked until all have done previous):</span><br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;going&nbsp;<span class="Statement">&lt;-</span>&nbsp;n&nbsp;<span class="Statement">=&lt;&lt;</span>&nbsp;readChan&nbsp;bChan<br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="Comment">----&nbsp;</span><span class="Todo">TODO</span><span class="Comment">: should we fork either of these:</span><br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writeChan&nbsp;rChan&nbsp;going&nbsp;<br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when&nbsp;going&nbsp;loop<br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
<br />
Finally we have the coordinator function that listens to the receiver Chan and&nbsp;<br />
pushes the next input down the (duplicated) broadcast chan after all nodes&nbsp;<br />
report in, keeping track of the number of active nodes after each round so it&nbsp;<br />
know how many will be reporting in through the Chan on the next round.<br />
<br />
<span class="Comment">&gt;</span>&nbsp;coordinator&nbsp;<span class="Statement">::</span>&nbsp;Chan&nbsp;a&nbsp;<span class="Statement">-&gt;</span>&nbsp;Chan&nbsp;Bool&nbsp;<span class="Statement">-&gt;</span>&nbsp;Int&nbsp;<span class="Statement">-&gt;</span>&nbsp;[a]&nbsp;<span class="Statement">-&gt;</span>&nbsp;IO&nbsp;()<br />
<span class="Comment">&gt;</span>&nbsp;coordinator&nbsp;bChan&nbsp;rChan&nbsp;<span class="Statement">=</span>&nbsp;loop&nbsp;&nbsp;<span class="Type">where</span>&nbsp;<br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;loop&nbsp;alive&nbsp;(a<span class="Statement">:</span>as)&nbsp;<span class="Statement">=</span>&nbsp;<span class="Statement">do</span><br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;putStr&nbsp;<span class="Constant">&quot;|&quot;</span>&nbsp;<span class="Comment">--DEBUG: visually delimit rounds</span><br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writeChan&nbsp;bChan&nbsp;a<br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rs&nbsp;<span class="Statement">&lt;-</span>&nbsp;getChanContents&nbsp;rChan<br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="Statement">let</span>&nbsp;died&nbsp;<span class="Statement">=</span>&nbsp;length&nbsp;<span class="Statement">$</span>&nbsp;filter&nbsp;not&nbsp;<span class="Statement">$</span>&nbsp;take&nbsp;alive&nbsp;rs<br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stillAlive&nbsp;<span class="Statement">=</span>&nbsp;alive&nbsp;<span class="Statement">-</span>&nbsp;died<br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when&nbsp;(stillAlive&nbsp;<span class="Statement">&gt;</span>&nbsp;<span class="Constant">0</span>)&nbsp;<span class="Statement">$</span>&nbsp;loop&nbsp;stillAlive&nbsp;as<br />
<span class="Comment">&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
<br />
And here we have some tests:<br />
<br />
<span class="Comment">&gt;</span>&nbsp;test2&nbsp;<span class="Statement">=</span>&nbsp;synchronize&nbsp;[nodeA,nodeB,nodeC]&nbsp;[<span class="Constant">1</span><span class="Statement">..</span>]<br />
<span class="Comment">&gt;</span><br />
<span class="Comment">&gt;</span>&nbsp;test3&nbsp;<span class="Statement">=</span>&nbsp;synchronize&nbsp;(concatMap&nbsp;(replicate&nbsp;<span class="Constant">3</span>)&nbsp;[nodeA,nodeB,nodeC])&nbsp;[<span class="Constant">1</span><span class="Statement">..</span>]<br />
<span class="Comment">&gt;</span><br />
<span class="Comment">&gt;</span>&nbsp;main&nbsp;<span class="Statement">=</span>&nbsp;test3<br />
<br />
<br />
If the above reminds you of Iteratee, I'm right with you. Will be exploring that<br />
next.<br />
<br />
Thanks!<br />
<br />
<br /></div></p>
]]></content:encoded>
			<wfw:commentRss>http://coder.bsimmons.name/blog/2011/02/synchronized-concurrent-io-actions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New version of directory-tree on hackage</title>
		<link>http://coder.bsimmons.name/blog/2011/02/new-version-of-directory-tree-on-hackage/</link>
		<comments>http://coder.bsimmons.name/blog/2011/02/new-version-of-directory-tree-on-hackage/#comments</comments>
		<pubDate>Sun, 13 Feb 2011 19:37:29 +0000</pubDate>
		<dc:creator>jberryman</dc:creator>
				<category><![CDATA[haskell]]></category>
		<category><![CDATA[IO]]></category>
		<category><![CDATA[library]]></category>
		<category><![CDATA[release]]></category>

		<guid isPermaLink="false">http://coder.bsimmons.name/blog/?p=538</guid>
		<description><![CDATA[<p>In response to a request and my own review I&#8217;ve modified my <a href="http://hackage.haskell.org/package/directory-tree">directory-tree</a> package as follows:</p>
<blockquote><p>    0.10.0</p>
<ul>
<li>Eq and Ord instances now compare on free &#8220;contents&#8221; type variable</li>
<li>we provide `equalShape` function for comparison of shape and</li></ul></blockquote><p>&#8230; <a href="http://coder.bsimmons.name/blog/2011/02/new-version-of-directory-tree-on-hackage/" class="read_more">   [ R E A D &#124; M O R E ]</a></p>]]></description>
			<content:encoded><![CDATA[<p>In response to a request and my own review I&#8217;ve modified my <a href="http://hackage.haskell.org/package/directory-tree">directory-tree</a> package as follows:</p>
<blockquote><p>    0.10.0</p>
<ul>
<li>Eq and Ord instances now compare on free &#8220;contents&#8221; type variable</li>
<li>we provide `equalShape` function for comparison of shape and filenames<br />
          of arbitrary trees (ignoring free &#8220;contents&#8221; variable)</li>
<li>provide a comparingShape used in sortDirShape</li>
<li>provide a `sortDirShape` function that sorts a tree, taking into<br />
          account the free file &#8220;contents&#8221; data</li>
</ul>
</blockquote>
<p>Now that equality and comparison functions that ignore the contents of Files are out of the Eq and Ord instances, we can make those types of comparisons on DirTrees of different types.</p>
<p>You can pick it up with a</p>
<blockquote><p>$ cabal install directory-tree</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://coder.bsimmons.name/blog/2011/02/new-version-of-directory-tree-on-hackage/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<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>
<p><strong>UPDATE</strong>: I&#8217;ve just released v0.9.0 of this package which has a number of sneaky changes and additions, most notably the inclusion of a <code>readDirectoryWithL</code> function that allows for lazy directory reading IO. This will let users work with a DirTree read from disk just as if it was a pure lazy data structure, while IO is done in the background as needed. No more exploding code! (hopefully)</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>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Page Caching using disk
Database Caching 6/15 queries in 0.266 seconds using disk

Served from: coder.bsimmons.name @ 2012-02-05 10:47:59 -->
