{"id":338,"date":"2007-07-16T02:49:00","date_gmt":"2007-07-16T09:49:00","guid":{"rendered":"http:\/\/www.elbeno.com\/blog\/?p=338"},"modified":"2007-07-29T12:37:59","modified_gmt":"2007-07-29T19:37:59","slug":"arboreal-haskell","status":"publish","type":"post","link":"https:\/\/www.elbeno.com\/blog\/?p=338","title":{"rendered":"Arboreal Haskell"},"content":{"rendered":"<p>(Chapter 7 of <em>The Haskell School of Expression<\/em> is about trees.)<\/p>\n<p>The first definition is of a tree with values stored only at the leaves, i.e.<\/p>\n<p><tt>data Tree a = Leaf a | Branch (Tree a) (Tree a)<\/tt><\/p>\n<p>It then gives a <tt>mapTree<\/tt> function (equivalent to <tt>map<\/tt> on a list), which is trivial, and functions <tt>fringe<\/tt>, <tt>treeSize<\/tt> and <tt>treeHeight<\/tt>, which return respectively the list of the leaf values, the number of leaves, and the max depth. In the text, these are defined in the usual recursive way. An exercise is to write a <tt>Tree<\/tt> equivalent of the <tt>fold<\/tt> function for lists. Which I think I managed:<\/p>\n<pre>foldTree :: (a -&gt; b -&gt; b) -&gt; (b -&gt; b -&gt; b) -&gt; b -&gt; Tree a -&gt; b\r\nfoldTree fLeaf _ init (Leaf x) = fLeaf x init\r\nfoldTree fLeaf fBranch init (Branch x y) = fBranch x' y'\r\n    where x' = foldTree fLeaf fBranch init x\r\n          y' = foldTree fLeaf fBranch init y<\/pre>\n<p>The trick was in recognising that I needed two functions, one for dealing with leaves and the other for dealing with branches (because <tt>(:)<\/tt> is a different type from <tt>(++)<\/tt> and both are used in <tt>fringe<\/tt>). Of course, the performance implication of all those list appends makes me think that in the real world, I&#8217;d write <tt>fringe<\/tt> using only <tt>(:)<\/tt>:<\/p>\n<pre>fastFringe :: Tree a -&gt; [a]\r\nfastFringe t = acc t []\r\n    where acc (Leaf x) l = x : l\r\n          acc (Branch x y) l = acc x (acc y l)<\/pre>\n<p>(It also occurs to me that <tt>fringe<\/tt> is more usually called <tt>flatten<\/tt> IME). The next exercises involved trees with internal values (not at the leaves), i.e.<\/p>\n<pre>data InternalTree a = ILeaf\r\n                    | IBranch a (InternalTree a) (InternalTree a)<\/pre>\n<p>This is a bit more like way I&#8217;m used to trees working, and the exercises were easier. <tt>InternalTree<\/tt> versions of <tt>zipWith<\/tt> and <tt>zip<\/tt> (defined in terms of <tt>zipWith<\/tt> of course) were easy, as were versions of <tt>take<\/tt> and <tt>takeWhile<\/tt>. I was impressed with the &#8220;magic&#8221; of the <tt>InternalTree<\/tt> version of <tt>repeat<\/tt>:<\/p>\n<pre>repeatInternalTree :: a -&gt; InternalTree a\r\nrepeatInternalTree a = t\r\n    where t = (IBranch a (t) (t))<\/pre>\n<p>There are two bits of magic here. First, this is an infinitely recursive definition. Haskell uses lazy evaluation, so this is designed to be used with <tt>takeTree<\/tt> or <tt>takeTreeWhile<\/tt>. The second piece of magic: where is the base case constructor (<tt>ILeaf<\/tt>) specified? It isn&#8217;t! Yet<\/p>\n<p><tt>takeTree 2 (repeatInternalTree 5)<\/tt><\/p>\n<p>returns<\/p>\n<p><tt>IBranch 5 (IBranch 5 ILeaf ILeaf) (IBranch 5 ILeaf ILeaf)<\/tt><\/p>\n<p>as hoped for, if not quite expected. The only thing I&#8217;m not really grokking right now are the <tt>InternalTree<\/tt> versions of <tt>foldr<\/tt> and possibly <tt>foldl<\/tt> (and possibly a third type of fold). I&#8217;ve got a feeling there is some higher-order function extractable that controls pre-, post-, or in-order node traversal on <tt>InternalTree<\/tt>, but I&#8217;m unsure of the structural differences of <tt>foldl<\/tt> and <tt>foldr<\/tt> when applied to trees. I am also puzzling a bit over the semantics of <tt>zipWith<\/tt> and <tt>zip<\/tt> when applied to trees with only leaf-node values.<\/p>\n<p>PS. Gleep = glorp.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>(Chapter 7 of The Haskell School of Expression is about trees.) The first definition is of a tree with values stored only at the leaves, i.e. data Tree a = Leaf a | Branch (Tree a) (Tree a) It then gives a mapTree function (equivalent to map on a list),&#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-338","post","type-post","status-publish","format-standard","hentry","category-haskell"],"_links":{"self":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/338","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=338"}],"version-history":[{"count":0,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/338\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=338"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=338"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=338"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}