<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/stylesheets/rss.css" type="text/css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Tom Moertel's Weblog: Tag refactoring</title>
    <link>http://blog.moertel.com/articles/tag/refactoring?tag=refactoring</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Quality rants on programming theory and stuff geeks like</description>
    <item>
      <title>Directory-tree printing in Haskell, part two: refactoring</title>
      <description>&lt;p&gt;In &lt;a href="http://blog.moertel.com/articles/2007/02/22/a-simple-directory-tree-printer-in-haskell"&gt;my previous article on writing a simple directory-tree printer in
Haskell&lt;/a&gt;,
I wrote a small program to recursively scan file-system
directories and print their contents as &lt;span class="caps"&gt;ASCII&lt;/span&gt;-art trees.  The
program made for an approachable example of how to use Haskell for
&amp;#8220;imperative&amp;#8221; tasks, but it has a few problems.&lt;/p&gt;


	&lt;p&gt;First, the directory-scanning logic and tree-printing logic are
intertwined.  Neither is reusable.  Second, both bits of logic are
rigid, specialized for this particular task.  Even if you could
reuse them, you wouldn&amp;#8217;t &lt;em&gt;want&lt;/em&gt; to.&lt;/p&gt;


	&lt;p&gt;In this article, the second in a series, we will explore ways to make
our original code more reusable.  We will separate the directory
scanning from the tree printing, harness the power of some old
friends from Haskell&amp;#8217;s libraries, and think about the costs
and benefits of our changes.&lt;/p&gt;


	&lt;h3&gt;The plan&lt;/h3&gt;


	&lt;p&gt;Recall our original directory tree&amp;#8211;listing solution, the
core of which I will reprint below:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varid'&gt;tlist&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt;
    &lt;span class='varid'&gt;visit&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='str'&gt;"/"&lt;/span&gt; &lt;span class='varop'&gt;`isPrefixOf`&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='keyword'&gt;then&lt;/span&gt; &lt;span class='str'&gt;""&lt;/span&gt; &lt;span class='keyword'&gt;else&lt;/span&gt; &lt;span class='str'&gt;"."&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='str'&gt;""&lt;/span&gt; &lt;span class='str'&gt;""&lt;/span&gt; &lt;span class='str'&gt;""&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt;

&lt;span class='varid'&gt;visit&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='varid'&gt;leader&lt;/span&gt; &lt;span class='varid'&gt;tie&lt;/span&gt; &lt;span class='varid'&gt;arm&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;
    &lt;span class='varid'&gt;putStrLn&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;leader&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='varid'&gt;arm&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='varid'&gt;tie&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
    &lt;span class='varid'&gt;visitChildren&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='str'&gt;"/"&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;leader&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='varid'&gt;extension&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
  &lt;span class='keyword'&gt;where&lt;/span&gt;
    &lt;span class='varid'&gt;extension&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;case&lt;/span&gt; &lt;span class='varid'&gt;arm&lt;/span&gt; &lt;span class='keyword'&gt;of&lt;/span&gt; &lt;span class='str'&gt;""&lt;/span&gt;  &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='str'&gt;""&lt;/span&gt;&lt;span class='layout'&gt;;&lt;/span&gt; &lt;span class='str'&gt;"`"&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='str'&gt;"    "&lt;/span&gt;&lt;span class='layout'&gt;;&lt;/span&gt; &lt;span class='keyword'&gt;_&lt;/span&gt;   &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='str'&gt;"|   "&lt;/span&gt;

&lt;span class='varid'&gt;visitChildren&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='varid'&gt;leader&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt;
    &lt;span class='varid'&gt;whenM&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;doesDirectoryExist&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varop'&gt;$&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;
        &lt;span class='varid'&gt;contents&lt;/span&gt; &lt;span class='keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='varid'&gt;getDirectoryContents&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt;
            &lt;span class='varop'&gt;`catch`&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='keyglyph'&gt;\&lt;/span&gt;&lt;span class='varid'&gt;e&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;return&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='varid'&gt;show&lt;/span&gt; &lt;span class='varid'&gt;e&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
        &lt;span class='keyword'&gt;let&lt;/span&gt; &lt;span class='varid'&gt;visibles&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;sort&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;filter&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varop'&gt;`notElem`&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"."&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='str'&gt;".."&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varop'&gt;$&lt;/span&gt; &lt;span class='varid'&gt;contents&lt;/span&gt;
            &lt;span class='varid'&gt;arms&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;replicate&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;length&lt;/span&gt; &lt;span class='varid'&gt;visibles&lt;/span&gt; &lt;span class='comment'&gt;-&lt;/span&gt; &lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='str'&gt;"|"&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"`"&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
        &lt;span class='varid'&gt;zipWithM_&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;visit&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='varid'&gt;leader&lt;/span&gt; &lt;span class='str'&gt;"-- "&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varid'&gt;arms&lt;/span&gt; &lt;span class='varid'&gt;visibles&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;The &lt;em&gt;tlist&lt;/em&gt; function kicks off the process for a particular
file-system &lt;em&gt;path&lt;/em&gt;, handing off to &lt;em&gt;visit&lt;/em&gt; which recursively descends the
directory tree from the root node.  The &lt;em&gt;visit&lt;/em&gt; function calls
&lt;em&gt;visitChildren&lt;/em&gt; to expand the subtree, if any, for each node visited.
The &lt;em&gt;visitChildren&lt;/em&gt; function, in turn, calls back to &lt;em&gt;visit&lt;/em&gt; to
repeat the process for each child in the subtree.
In effect, we are traversing the tree rooted at &lt;em&gt;path&lt;/em&gt;, printing each
node in passing.&lt;/p&gt;


	&lt;p&gt;To separate the traversal part from the printing part, we will
introduce a tree data structure.  The file system&amp;#8211;traversal code
will emit a tree, and the tree-showing code will consume a tree.  We
will rewrite our old &lt;em&gt;tlist&lt;/em&gt; function, which we might as well rename to
the more descriptive &lt;em&gt;traverseAndPrint&lt;/em&gt;, to glue the two pieces
together with the tree serving as glue:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varid'&gt;traverseAndPrint&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Path&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;IO&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;span class='varid'&gt;traverseAndPrint&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;
    &lt;span class='varid'&gt;tree&lt;/span&gt; &lt;span class='keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='varid'&gt;fsTraverse&lt;/span&gt; &lt;span class='varid'&gt;root&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt;
    &lt;span class='varid'&gt;putStrLn&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;showTree&lt;/span&gt; &lt;span class='varid'&gt;tree&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
  &lt;span class='keyword'&gt;where&lt;/span&gt;
    &lt;span class='varid'&gt;root&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='str'&gt;"/"&lt;/span&gt; &lt;span class='varop'&gt;`isPrefixOf`&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='keyword'&gt;then&lt;/span&gt; &lt;span class='str'&gt;""&lt;/span&gt; &lt;span class='keyword'&gt;else&lt;/span&gt; &lt;span class='str'&gt;"."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;That&amp;#8217;s the plan.  Now let&amp;#8217;s carry it out.&lt;/p&gt;&lt;h3&gt; Step 1:  Introduce the intermediate tree data structure&lt;/h3&gt;


	&lt;p&gt;To make our desired separation possible, let&amp;#8217;s introduce the tree data
structure.  Conveniently enough, the &lt;code&gt;Data.Tree&lt;/code&gt; library
provides the structure for us:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='keyword'&gt;data&lt;/span&gt; &lt;span class='conid'&gt;Tree&lt;/span&gt; &lt;span class='varid'&gt;a&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='conid'&gt;Node&lt;/span&gt; &lt;span class='layout'&gt;{&lt;/span&gt;&lt;span class='varid'&gt;rootLabel&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='varid'&gt;a&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;subForest&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Forest&lt;/span&gt; &lt;span class='varid'&gt;a&lt;/span&gt;&lt;span class='layout'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Let&amp;#8217;s also define some descriptive type synonyms to help us think about
our data:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='keyword'&gt;type&lt;/span&gt; &lt;span class='conid'&gt;Path&lt;/span&gt;       &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt;           &lt;span class='comment'&gt;-- path&lt;/span&gt;
&lt;span class='keyword'&gt;type&lt;/span&gt; &lt;span class='conid'&gt;DentName&lt;/span&gt;   &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt;           &lt;span class='comment'&gt;-- directory-entry name&lt;/span&gt;
&lt;span class='keyword'&gt;type&lt;/span&gt; &lt;span class='conid'&gt;DirNode&lt;/span&gt;    &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;Path&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;DentName&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='comment'&gt;-- directory-path/dentname pair&lt;/span&gt;
&lt;span class='keyword'&gt;type&lt;/span&gt; &lt;span class='conid'&gt;DirTree&lt;/span&gt;    &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='conid'&gt;Tree&lt;/span&gt; &lt;span class='conid'&gt;DentName&lt;/span&gt;    &lt;span class='comment'&gt;-- file-system tree&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;(Unlike last time, in this article I&amp;#8217;ll place type annotations
on all top-level declarations to help you see how the data
flows between the pieces of our code.)&lt;/p&gt;


	&lt;p&gt;To give you an idea of what the tree structure looks like,
here&amp;#8217;s an example &lt;em&gt;DirTree&lt;/em&gt; value:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varid'&gt;exampleTree&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;DirTree&lt;/span&gt;
&lt;span class='varid'&gt;exampleTree&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='conid'&gt;Node&lt;/span&gt; &lt;span class='str'&gt;"root"&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;
                &lt;span class='conid'&gt;Node&lt;/span&gt; &lt;span class='str'&gt;"subdir1"&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;
                  &lt;span class='conid'&gt;Node&lt;/span&gt; &lt;span class='str'&gt;"file1.1"&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
                &lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;Node&lt;/span&gt; &lt;span class='str'&gt;"file1.2"&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
                &lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;Node&lt;/span&gt; &lt;span class='str'&gt;"subdir1.3"&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;
                    &lt;span class='conid'&gt;Node&lt;/span&gt; &lt;span class='str'&gt;"file1.3.1"&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt; &lt;span class='keyglyph'&gt;]&lt;/span&gt; &lt;span class='keyglyph'&gt;]&lt;/span&gt;
              &lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;Node&lt;/span&gt; &lt;span class='str'&gt;"file1"&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt; &lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Now let&amp;#8217;s revise our old code to show a tree in this structure.&lt;/p&gt;


	&lt;h3&gt; Step 2:  Write the tree-showing code&lt;/h3&gt;


	&lt;p&gt;This step is easy.  We just copy and paste our old code, remove the
I/O related bits, and tweak for clarity:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='comment'&gt;-- Purely functional tree-to-string formatting&lt;/span&gt;

&lt;span class='varid'&gt;showTree&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Tree&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt;
&lt;span class='varid'&gt;showTree&lt;/span&gt; &lt;span class='varid'&gt;t&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;unlines&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;showNode&lt;/span&gt; &lt;span class='str'&gt;""&lt;/span&gt; &lt;span class='str'&gt;""&lt;/span&gt; &lt;span class='str'&gt;""&lt;/span&gt; &lt;span class='varid'&gt;t&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;

&lt;span class='varid'&gt;showNode&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;Tree&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='conid'&gt;String&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;span class='varid'&gt;showNode&lt;/span&gt; &lt;span class='varid'&gt;leader&lt;/span&gt; &lt;span class='varid'&gt;tie&lt;/span&gt; &lt;span class='varid'&gt;arm&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;
    &lt;span class='varid'&gt;nodeRep&lt;/span&gt; &lt;span class='conop'&gt;:&lt;/span&gt; &lt;span class='varid'&gt;showChildren&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;leader&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='varid'&gt;extension&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
  &lt;span class='keyword'&gt;where&lt;/span&gt;
    &lt;span class='varid'&gt;nodeRep&lt;/span&gt;   &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;leader&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='varid'&gt;arm&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='varid'&gt;tie&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='varid'&gt;rootLabel&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt;
    &lt;span class='varid'&gt;extension&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;case&lt;/span&gt; &lt;span class='varid'&gt;arm&lt;/span&gt; &lt;span class='keyword'&gt;of&lt;/span&gt; &lt;span class='str'&gt;""&lt;/span&gt;  &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='str'&gt;""&lt;/span&gt;&lt;span class='layout'&gt;;&lt;/span&gt; &lt;span class='str'&gt;"`"&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='str'&gt;"    "&lt;/span&gt;&lt;span class='layout'&gt;;&lt;/span&gt; &lt;span class='keyword'&gt;_&lt;/span&gt;   &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='str'&gt;"|   "&lt;/span&gt;

&lt;span class='varid'&gt;showChildren&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Tree&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='conid'&gt;String&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;span class='varid'&gt;showChildren&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt; &lt;span class='varid'&gt;leader&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt;
    &lt;span class='keyword'&gt;let&lt;/span&gt; &lt;span class='varid'&gt;children&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;subForest&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt;
        &lt;span class='varid'&gt;arms&lt;/span&gt;     &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;replicate&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;length&lt;/span&gt; &lt;span class='varid'&gt;children&lt;/span&gt; &lt;span class='comment'&gt;-&lt;/span&gt; &lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='str'&gt;"|"&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"`"&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
    &lt;span class='keyword'&gt;in&lt;/span&gt;  &lt;span class='varid'&gt;concat&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;zipWith&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;showNode&lt;/span&gt; &lt;span class='varid'&gt;leader&lt;/span&gt; &lt;span class='str'&gt;"-- "&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varid'&gt;arms&lt;/span&gt; &lt;span class='varid'&gt;children&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;There are two main differences between this code and the old code.
First, instead of processing directory nodes in the file system, we
are processing tree nodes of the &lt;em&gt;Tree&lt;/em&gt; data type.  Second, because
the code is pure, that is, free of side effects, its result is a
&lt;em&gt;String&lt;/em&gt;, not an &lt;em&gt;IO&lt;/em&gt; action.&lt;/p&gt;


	&lt;p&gt;Lets take this code for a spin in GHCi.  We&amp;#8217;ll ask it to show
our example tree from earlier in the article.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;Ok, modules loaded: Main.
*Main&amp;gt; putStr (showTree exampleTree)
root
|-- subdir1
|   |-- file1.1
|   |-- file1.2
|   `-- subdir1.3
|       `-- file1.3.1
`-- file1
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Great.  Let&amp;#8217;s move on.&lt;/p&gt;


	&lt;h3&gt; Step 3:  Write the directory-traversal code&lt;/h3&gt;


	&lt;p&gt;In this step, we want to write the code that recursively scans
(traverses) a directory hierarchy and returns a &lt;em&gt;DirTree&lt;/em&gt; that
represents the hierarchy.  The following code, which does just
that, is a straightforward extraction of our old code&amp;#8217;s
&lt;em&gt;visit&lt;/em&gt; and &lt;em&gt;visitChildren&lt;/em&gt; functions:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='comment'&gt;-- Effectful directory-traversal code that returns a tree&lt;/span&gt;
&lt;span class='comment'&gt;-- representing the directory hierarchy rooted at 'path/node'.&lt;/span&gt;

&lt;span class='varid'&gt;fsTraverse&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Path&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;DentName&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;IO&lt;/span&gt; &lt;span class='conid'&gt;DirTree&lt;/span&gt;
&lt;span class='varid'&gt;fsTraverse&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt;
    &lt;span class='conid'&gt;Node&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt; &lt;span class='varop'&gt;`liftM`&lt;/span&gt; &lt;span class='varid'&gt;fsTraverseChildren&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='str'&gt;"/"&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;

&lt;span class='varid'&gt;fsTraverseChildren&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Path&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;IO&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;Forest&lt;/span&gt; &lt;span class='conid'&gt;DentName&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;span class='varid'&gt;fsTraverseChildren&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt;
    &lt;span class='varid'&gt;mapM&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;uncurry&lt;/span&gt; &lt;span class='varid'&gt;fsTraverse&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varop'&gt;=&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='varid'&gt;fsGetChildren&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;The &lt;em&gt;fsTraverse&lt;/em&gt; function takes advantage of &lt;em&gt;liftM&lt;/em&gt; to &amp;#8220;lift&amp;#8221; the
pure function (&lt;em&gt;Node node&lt;/em&gt;) into the &lt;em&gt;IO&lt;/em&gt; monad, where it
is applied to the result of the effectful &lt;em&gt;fsTraverseChildren&lt;/em&gt;
function.  It is shorter and more communicative of
our intent than the following equivalent code:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='keyword'&gt;do&lt;/span&gt; &lt;span class='varid'&gt;childForest&lt;/span&gt; &lt;span class='keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='varid'&gt;fsTraverseChildren&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='str'&gt;"/"&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
   &lt;span class='varid'&gt;return&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;Node&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt; &lt;span class='varid'&gt;childForest&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;While extracting these functions from our original code, I took the
liberty of factoring out the code that grabs the contents of a
directory.  This code now lives in its own helper function:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='comment'&gt;-- helper to get traversable directory entries&lt;/span&gt;

&lt;span class='varid'&gt;fsGetChildren&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Path&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;IO&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='conid'&gt;DirNode&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;span class='varid'&gt;fsGetChildren&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;
    &lt;span class='varid'&gt;contents&lt;/span&gt; &lt;span class='keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='varid'&gt;getDirectoryContents&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='varop'&gt;`catch`&lt;/span&gt; &lt;span class='varid'&gt;const&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;return&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
    &lt;span class='keyword'&gt;let&lt;/span&gt; &lt;span class='varid'&gt;visibles&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;sort&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;filter&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varop'&gt;`notElem`&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"."&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='str'&gt;".."&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varop'&gt;$&lt;/span&gt; &lt;span class='varid'&gt;contents&lt;/span&gt;
    &lt;span class='varid'&gt;return&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;map&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varid'&gt;visibles&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;This bit of code differs from the code in the previous article in that
it treats any error encountered when scanning a directory as if the
directory were empty.  That&amp;#8217;s what the&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varop'&gt;...&lt;/span&gt; &lt;span class='varop'&gt;`catch`&lt;/span&gt; &lt;span class='varid'&gt;const&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;return&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;addendum does.  It says that any error caught while scanning the
directory will be handled by a constant policy, that of returning an
empty list.&lt;/p&gt;


	&lt;p&gt;This policy tends to be what we want in practice because the two most
common errors we expect to encounter here will be &amp;#8220;oops, that&amp;#8217;s a
file, so it can&amp;#8217;t have children&amp;#8221; and &amp;#8220;oops, you&amp;#8217;re not allowed to scan
that directory.&amp;#8221;  This error-handling policy will, however, throw away
potentially useful information, say, in the rare case that the error
is something like &amp;#8220;oops, your hard drive caught on fire and is about
to explode: start running now.&amp;#8221;  (Maybe we&amp;#8217;ll revisit our policy
later.)&lt;/p&gt;


	&lt;h3&gt; Step 4: Connect the traversal code to the printing code&lt;/h3&gt;


	&lt;p&gt;We can traverse file-system hierarchies to produce trees.  We can
print trees.  To traverse &lt;em&gt;and&lt;/em&gt; print a hierarchy, then, requires
nothing but a little glue.  Conveniently, we have already written
the needed glue, &lt;em&gt;traverseAndPrint&lt;/em&gt;, when we formulated our plan.
Here is a slightly more concise version:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varid'&gt;traverseAndPrint&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Path&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;IO&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;span class='varid'&gt;traverseAndPrint&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt;
    &lt;span class='varid'&gt;putStr&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;showTree&lt;/span&gt; &lt;span class='varop'&gt;=&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='varid'&gt;fsTraverse&lt;/span&gt; &lt;span class='varid'&gt;root&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt;
  &lt;span class='keyword'&gt;where&lt;/span&gt;
    &lt;span class='varid'&gt;root&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='str'&gt;"/"&lt;/span&gt; &lt;span class='varop'&gt;`isPrefixOf`&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='keyword'&gt;then&lt;/span&gt; &lt;span class='str'&gt;""&lt;/span&gt; &lt;span class='keyword'&gt;else&lt;/span&gt; &lt;span class='str'&gt;"."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Now we have a complete solution.  Let&amp;#8217;s give it a spin in
GHCi.  I&amp;#8217;ll traverse and print the &lt;a href="http://darcs.net/"&gt;Darcs&lt;/a&gt; repository
that holds the code for this article.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;*Main&amp;gt; traverseAndPrint "_darcs" 
_darcs
|-- inventories
|-- inventory
|-- patches
|   |-- 20070226210515-8fbd9-42e4...74102.gz
|   |-- 20070226210634-8fbd9-86cd...490ef.gz
|   |-- 20070227053004-8fbd9-122b...5023d.gz
|   |--   [ entries omitted for brevity ]
|   |-- 20070227233827-8fbd9-94ab...4852f.gz
|   |-- 20070228181747-8fbd9-db9b...e8ce6.gz
|   |-- 20070303192612-8fbd9-ff2a...3d7bb.gz
|   `-- pending
|-- prefs
|   |-- author
|   |-- binaries
|   |-- boring
|   `-- motd
`-- pristine
    |-- Makefile
    `-- tlist.hs
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;(I shortened some of the longer file names to prevent them from escaping
the narrow text column of my blog.)&lt;/p&gt;


	&lt;p&gt;Very well.  Now let&amp;#8217;s see if we can tighten our code.&lt;/p&gt;


	&lt;h3&gt; Step 5: Simplify&lt;/h3&gt;


	&lt;p&gt;One benefit of breaking monolithic code into composable pieces is that
the pieces are often amenable to further simplification.  Our
&lt;em&gt;fsTraverse&lt;/em&gt; function, for example, was extracted from our old code,
where it combined directory-scanning and tree-printing knowledge. Now,
the tree-printing knowledge factored out, it combines
directory-scanning and tree-&lt;em&gt;building&lt;/em&gt; knowledge.  But the &lt;em&gt;Tree&lt;/em&gt;
data type, as you might expect, already contains that second piece
of knowledge.  So we can simplify &lt;em&gt;fsTraverse&lt;/em&gt; further by removing this
duplicated know-how.&lt;/p&gt;


	&lt;p&gt;The function that makes the simplification possible is &lt;em&gt;unfoldTreeM&lt;/em&gt;:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varop'&gt;*&lt;/span&gt;&lt;span class='conid'&gt;Main&lt;/span&gt;&lt;span class='varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='conop'&gt;:&lt;/span&gt;&lt;span class='varid'&gt;t&lt;/span&gt; &lt;span class='varid'&gt;unfoldTreeM&lt;/span&gt;
&lt;span class='varid'&gt;unfoldTreeM&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;Monad&lt;/span&gt; &lt;span class='varid'&gt;m&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='keyglyph'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;b&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;m&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;a&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='varid'&gt;b&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;b&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;m&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;Tree&lt;/span&gt; &lt;span class='varid'&gt;a&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;This function, which is parametrized by a &lt;em&gt;step&lt;/em&gt; function, grows a
tree from a single seed value.  The &lt;em&gt;step&lt;/em&gt; function is what we provide
to guide each step of the process.  It consumes a seed value and
produces a tree node and a list of seeds from which the node&amp;#8217;s
children can be grown.  The &lt;em&gt;unfoldTreeM&lt;/em&gt; function calls our step
function recursively on the seeds until the entire tree is grown.  (If
our step function were not effectful, requiring I/O, we could use the
pure function &lt;em&gt;unfoldTree&lt;/em&gt; instead of &lt;em&gt;unfoldTreeM&lt;/em&gt; to build our
trees.)&lt;/p&gt;


	&lt;p&gt;Our directory-scanning step function parallels our earlier
&lt;em&gt;fsTraverse&lt;/em&gt; function, which I will reprint below for comparison, but
eliminates knowledge of the &lt;em&gt;Tree&lt;/em&gt; data structure.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varid'&gt;fsTraverse&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Path&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;DentName&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;IO&lt;/span&gt; &lt;span class='conid'&gt;DirTree&lt;/span&gt;
&lt;span class='varid'&gt;fsTraverse&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt;
    &lt;span class='conid'&gt;Node&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt; &lt;span class='varop'&gt;`liftM`&lt;/span&gt; &lt;span class='varid'&gt;fsTraverseChildren&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='str'&gt;"/"&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;

&lt;span class='varid'&gt;fsTraverseStep&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;DirNode&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;IO&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;DentName&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='conid'&gt;DirNode&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;span class='varid'&gt;fsTraverseStep&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;path&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt;
    &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt; &lt;span class='varop'&gt;`liftM`&lt;/span&gt; &lt;span class='varid'&gt;fsGetChildren&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='str'&gt;"/"&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Note that a &lt;em&gt;DirNode&lt;/em&gt; is simply a (&lt;em&gt;Path&lt;/em&gt;, &lt;em&gt;DentName&lt;/em&gt;) pair.  Thus the
first argument of &lt;em&gt;fsTraverseStep&lt;/em&gt; is equivalent to the first two
arguments of &lt;em&gt;fsTraverse&lt;/em&gt;.  This pairing is convenient because the
seed values we produce are also &lt;em&gt;DirNode&lt;/em&gt;s, and this parity is
required by the type of &lt;em&gt;unfoldTreeM&lt;/em&gt;.  (Had our step function
retained the two-argument form, we could have used the &lt;em&gt;uncurry&lt;/em&gt;
combinator to transform it into the form required for &lt;em&gt;unfoldTreeM&lt;/em&gt;.
Later, we&amp;#8217;ll use &lt;em&gt;curry&lt;/em&gt; to perform the opposite transformation.)&lt;/p&gt;


	&lt;p&gt;Now we can use &lt;em&gt;unfoldTreeM&lt;/em&gt; to build file-system hierarchies.
Let&amp;#8217;s try it using GHCi:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varop'&gt;*&lt;/span&gt;&lt;span class='conid'&gt;Main&lt;/span&gt;&lt;span class='varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;unfoldTreeM&lt;/span&gt; &lt;span class='varid'&gt;fsTraverseStep&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='str'&gt;"."&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='str'&gt;"_darcs"&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;span class='conid'&gt;Node&lt;/span&gt; &lt;span class='layout'&gt;{&lt;/span&gt;&lt;span class='varid'&gt;rootLabel&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='str'&gt;"_darcs"&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;subForest&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt; &lt;span class='comment'&gt;{- more nodes here -}&lt;/span&gt; &lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;The final step of our simplification is to rewrite &lt;em&gt;fsTraverse&lt;/em&gt;
in terms of &lt;em&gt;unfoldTreeM&lt;/em&gt;:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varid'&gt;fsTraverse&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Path&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;DentName&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;IO&lt;/span&gt; &lt;span class='conid'&gt;DirTree&lt;/span&gt;
&lt;span class='varid'&gt;fsTraverse&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;curry&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;unfoldTreeM&lt;/span&gt; &lt;span class='varid'&gt;fsTraverseStep&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Note the use of &lt;em&gt;curry&lt;/em&gt; to adapt &lt;em&gt;unfoldTreeM&lt;/em&gt;&amp;#8217;s arguments
into the form implied by &lt;em&gt;fsTraverse&lt;/em&gt;&amp;#8217;s type signature.&lt;/p&gt;


	&lt;h3&gt; The final code (for now)&lt;/h3&gt;


	&lt;p&gt;Our simplification done, here is our complete, refactored
program:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='keyword'&gt;module&lt;/span&gt; &lt;span class='conid'&gt;Main&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;main&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='keyword'&gt;where&lt;/span&gt;

&lt;span class='keyword'&gt;import&lt;/span&gt; &lt;span class='conid'&gt;Control&lt;/span&gt;&lt;span class='varop'&gt;.&lt;/span&gt;&lt;span class='conid'&gt;Monad&lt;/span&gt;
&lt;span class='keyword'&gt;import&lt;/span&gt; &lt;span class='conid'&gt;Data&lt;/span&gt;&lt;span class='varop'&gt;.&lt;/span&gt;&lt;span class='conid'&gt;List&lt;/span&gt;
&lt;span class='keyword'&gt;import&lt;/span&gt; &lt;span class='conid'&gt;Data&lt;/span&gt;&lt;span class='varop'&gt;.&lt;/span&gt;&lt;span class='conid'&gt;Tree&lt;/span&gt;
&lt;span class='keyword'&gt;import&lt;/span&gt; &lt;span class='conid'&gt;System&lt;/span&gt;&lt;span class='varop'&gt;.&lt;/span&gt;&lt;span class='conid'&gt;Directory&lt;/span&gt;
&lt;span class='keyword'&gt;import&lt;/span&gt; &lt;span class='conid'&gt;System&lt;/span&gt;&lt;span class='varop'&gt;.&lt;/span&gt;&lt;span class='conid'&gt;Environment&lt;/span&gt;

&lt;span class='comment'&gt;-- Some convenient type synonyms&lt;/span&gt;

&lt;span class='keyword'&gt;type&lt;/span&gt; &lt;span class='conid'&gt;Path&lt;/span&gt;       &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt;           &lt;span class='comment'&gt;-- path&lt;/span&gt;
&lt;span class='keyword'&gt;type&lt;/span&gt; &lt;span class='conid'&gt;DentName&lt;/span&gt;   &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt;           &lt;span class='comment'&gt;-- directory-entry name&lt;/span&gt;
&lt;span class='keyword'&gt;type&lt;/span&gt; &lt;span class='conid'&gt;DirNode&lt;/span&gt;    &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;Path&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;DentName&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='comment'&gt;-- directory-path/dentname pair&lt;/span&gt;
&lt;span class='keyword'&gt;type&lt;/span&gt; &lt;span class='conid'&gt;DirTree&lt;/span&gt;    &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='conid'&gt;Tree&lt;/span&gt; &lt;span class='conid'&gt;DentName&lt;/span&gt;    &lt;span class='comment'&gt;-- file-system tree&lt;/span&gt;

&lt;span class='comment'&gt;-- High-level program logic:  get args and print a tree for each&lt;/span&gt;

&lt;span class='varid'&gt;main&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;IO&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;span class='varid'&gt;main&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;
    &lt;span class='varid'&gt;args&lt;/span&gt; &lt;span class='keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='varid'&gt;getArgs&lt;/span&gt;
    &lt;span class='varid'&gt;mapM_&lt;/span&gt; &lt;span class='varid'&gt;traverseAndPrint&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='varid'&gt;null&lt;/span&gt; &lt;span class='varid'&gt;args&lt;/span&gt; &lt;span class='keyword'&gt;then&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"."&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt; &lt;span class='keyword'&gt;else&lt;/span&gt; &lt;span class='varid'&gt;args&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;

&lt;span class='varid'&gt;traverseAndPrint&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Path&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;IO&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;span class='varid'&gt;traverseAndPrint&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt;
    &lt;span class='varid'&gt;putStr&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;showTree&lt;/span&gt; &lt;span class='varop'&gt;=&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='varid'&gt;fsTraverse&lt;/span&gt; &lt;span class='varid'&gt;root&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt;
  &lt;span class='keyword'&gt;where&lt;/span&gt;
    &lt;span class='varid'&gt;root&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='str'&gt;"/"&lt;/span&gt; &lt;span class='varop'&gt;`isPrefixOf`&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='keyword'&gt;then&lt;/span&gt; &lt;span class='str'&gt;""&lt;/span&gt; &lt;span class='keyword'&gt;else&lt;/span&gt; &lt;span class='str'&gt;"."&lt;/span&gt;

&lt;span class='comment'&gt;-- Effectful tree-builder for file-system hierarchies&lt;/span&gt;

&lt;span class='varid'&gt;fsTraverse&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Path&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;DentName&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;IO&lt;/span&gt; &lt;span class='conid'&gt;DirTree&lt;/span&gt;
&lt;span class='varid'&gt;fsTraverse&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;curry&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;unfoldTreeM&lt;/span&gt; &lt;span class='varid'&gt;fsTraverseStep&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;

&lt;span class='varid'&gt;fsTraverseStep&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;DirNode&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;IO&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;DentName&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='conid'&gt;DirNode&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;span class='varid'&gt;fsTraverseStep&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;path&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt;
    &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt; &lt;span class='varop'&gt;`liftM`&lt;/span&gt; &lt;span class='varid'&gt;fsGetChildren&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='str'&gt;"/"&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;

&lt;span class='comment'&gt;-- Helper to get traversable directory entries&lt;/span&gt;

&lt;span class='varid'&gt;fsGetChildren&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Path&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;IO&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='conid'&gt;DirNode&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;span class='varid'&gt;fsGetChildren&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;
    &lt;span class='varid'&gt;contents&lt;/span&gt; &lt;span class='keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='varid'&gt;getDirectoryContents&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt; &lt;span class='varop'&gt;`catch`&lt;/span&gt; &lt;span class='varid'&gt;const&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;return&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
    &lt;span class='keyword'&gt;let&lt;/span&gt; &lt;span class='varid'&gt;visibles&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;sort&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;filter&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varop'&gt;`notElem`&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"."&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='str'&gt;".."&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varop'&gt;$&lt;/span&gt; &lt;span class='varid'&gt;contents&lt;/span&gt;
    &lt;span class='varid'&gt;return&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;map&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varid'&gt;path&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varid'&gt;visibles&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;

&lt;span class='comment'&gt;-- Purely functional tree-to-string formatting&lt;/span&gt;

&lt;span class='varid'&gt;showTree&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Tree&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt;
&lt;span class='varid'&gt;showTree&lt;/span&gt; &lt;span class='varid'&gt;t&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;unlines&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;showNode&lt;/span&gt; &lt;span class='str'&gt;""&lt;/span&gt; &lt;span class='str'&gt;""&lt;/span&gt; &lt;span class='str'&gt;""&lt;/span&gt; &lt;span class='varid'&gt;t&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;

&lt;span class='varid'&gt;showNode&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;Tree&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='conid'&gt;String&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;span class='varid'&gt;showNode&lt;/span&gt; &lt;span class='varid'&gt;leader&lt;/span&gt; &lt;span class='varid'&gt;tie&lt;/span&gt; &lt;span class='varid'&gt;arm&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt;
    &lt;span class='varid'&gt;nodeRep&lt;/span&gt; &lt;span class='conop'&gt;:&lt;/span&gt; &lt;span class='varid'&gt;showChildren&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;leader&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='varid'&gt;extension&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
  &lt;span class='keyword'&gt;where&lt;/span&gt;
    &lt;span class='varid'&gt;nodeRep&lt;/span&gt;   &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;leader&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='varid'&gt;arm&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='varid'&gt;tie&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='varid'&gt;rootLabel&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt;
    &lt;span class='varid'&gt;extension&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;case&lt;/span&gt; &lt;span class='varid'&gt;arm&lt;/span&gt; &lt;span class='keyword'&gt;of&lt;/span&gt; &lt;span class='str'&gt;""&lt;/span&gt;  &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='str'&gt;""&lt;/span&gt;&lt;span class='layout'&gt;;&lt;/span&gt; &lt;span class='str'&gt;"`"&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='str'&gt;"    "&lt;/span&gt;&lt;span class='layout'&gt;;&lt;/span&gt; &lt;span class='keyword'&gt;_&lt;/span&gt;   &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='str'&gt;"|   "&lt;/span&gt;

&lt;span class='varid'&gt;showChildren&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Tree&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='conid'&gt;String&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;span class='varid'&gt;showChildren&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt; &lt;span class='varid'&gt;leader&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt;
    &lt;span class='keyword'&gt;let&lt;/span&gt; &lt;span class='varid'&gt;children&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;subForest&lt;/span&gt; &lt;span class='varid'&gt;node&lt;/span&gt;
        &lt;span class='varid'&gt;arms&lt;/span&gt;     &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;replicate&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;length&lt;/span&gt; &lt;span class='varid'&gt;children&lt;/span&gt; &lt;span class='comment'&gt;-&lt;/span&gt; &lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='str'&gt;"|"&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"`"&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
    &lt;span class='keyword'&gt;in&lt;/span&gt;  &lt;span class='varid'&gt;concat&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;zipWith&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;showNode&lt;/span&gt; &lt;span class='varid'&gt;leader&lt;/span&gt; &lt;span class='str'&gt;"-- "&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varid'&gt;arms&lt;/span&gt; &lt;span class='varid'&gt;children&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3&gt; Let&amp;#8217;s review&lt;/h3&gt;


	&lt;p&gt;We have refactored our original, small, monolithic solution into a
collection of more reusable code snippets.  The total &amp;#8220;cost&amp;#8221; of our
new solution is certainly higher than before &amp;#8211; the code is twice as
long &amp;#8211; but we can reasonably expect that by reusing this code
we can reduce the cost of future solutions that might require similar
functionality.&lt;/p&gt;


	&lt;p&gt;Say, for example, we need to write some code to count the files and
directories within a hierarchy.  Building upon our new code, we can
write it easily, as a one-liner in GHCi even:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varop'&gt;*&lt;/span&gt;&lt;span class='conid'&gt;Main&lt;/span&gt;&lt;span class='varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;print&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;length&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;flatten&lt;/span&gt; &lt;span class='varop'&gt;=&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='varid'&gt;fsTraverse&lt;/span&gt; &lt;span class='str'&gt;"."&lt;/span&gt; &lt;span class='str'&gt;"_darcs"&lt;/span&gt;
&lt;span class='num'&gt;27&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Still, there is much about our code that could be better.  First,
unlike our old solution, our new solution builds the entire tree
before it begins to emit output.  If the tree is large, its memory
footprint could be daunting.  Second, our error-handling policy is
mildly embarrassing.  Third, our directory-traversal code isn&amp;#8217;t
flexible.  What if we want to get the size of each file we visit
during the traversal?  Right now, there&amp;#8217;s no easy way to do it.&lt;/p&gt;


	&lt;p&gt;Fortunately, we aren&amp;#8217;t done yet.  Haskell offers us many
opportunities for abstraction and parametrization that we are not
taking advantage of.  In the next article, we&amp;#8217;ll exploit a
few of these opportunities to make our code a little more
flexible and a little more idiomatic.&lt;/p&gt;


	&lt;p&gt;See you then.&lt;/p&gt;</description>
      <pubDate>Wed, 07 Mar 2007 16:04:00 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:228f4d10-a4a2-4284-a648-4f741a82dc66</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2007/03/07/directory-tree-printing-in-haskell-part-two-refactoring</link>
      <category>haskell</category>
      <category>haskell</category>
      <category>trees</category>
      <category>io</category>
      <category>refactoring</category>
      <category>directory_tree_series</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/401</trackback:ping>
    </item>
  </channel>
</rss>
