<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3679812208800765969</id><updated>2012-01-20T14:57:00.309-08:00</updated><title type='text'>monoidal</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://monoidal.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3679812208800765969/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://monoidal.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>g</name><uri>http://www.blogger.com/profile/04686862403622560424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>8</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3679812208800765969.post-6197913852570313379</id><published>2011-10-27T11:42:00.000-07:00</published><updated>2011-10-27T11:56:34.895-07:00</updated><title type='text'>Kind polymorphism - a draft</title><content type='html'>I extended the &lt;a href="http://monoidal.blogspot.com/2010/07/kind-polymorphism-in-action.html"&gt;post on kind polymorphism&lt;/a&gt; to Omega, and I'm rather satisfied - I captured 10 different senses of monoids, used level polymorphism and type functions on the way.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;sumMonoid      :: Monoid Hask Int                 -- monoid&lt;br /&gt;maybeMonad     :: Monoid EndHask Maybe            -- monad&lt;br /&gt;envComonad     :: Monoid CoEndHask (Env s)        -- comonad&lt;br /&gt;haskCat        :: Monoid Graph (-&gt;)               -- category&lt;br /&gt;ixState        :: Monoid Indexed IxState          -- indexed monad&lt;br /&gt;ixStore        :: Monoid CoIndexed IxStore        -- indexed comonad&lt;br /&gt;intRing        :: Monoid Ab Int                   -- ring&lt;br /&gt;sumCMonoid     :: Monoid Monoids Int              -- commutative monoid&lt;br /&gt;complexAlgebra :: Monoid (VSpaces Float) Complex  -- R-algebra&lt;br /&gt;EndHask''      :: Monoid' Cats (*0 ~&gt; *0)         -- monoidal category&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A draft is available &lt;a href="http://students.mimuw.edu.pl/~kg262935/kpol/Author.pdf"&gt;here&lt;/a&gt; and Omega source code is available &lt;a href="http://students.mimuw.edu.pl/~kg262935/kpol/prog.hs"&gt;here&lt;/a&gt;. There are still things that can be improved and researched on.&lt;br /&gt;&lt;br /&gt;Also, see a new paper on kind system: &lt;a href="http://research.microsoft.com/en-us/people/dimitris/fc-kind-poly.pdf"&gt;Giving Haskell a Promotion&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3679812208800765969-6197913852570313379?l=monoidal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://monoidal.blogspot.com/feeds/6197913852570313379/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3679812208800765969&amp;postID=6197913852570313379' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3679812208800765969/posts/default/6197913852570313379'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3679812208800765969/posts/default/6197913852570313379'/><link rel='alternate' type='text/html' href='http://monoidal.blogspot.com/2011/10/kind-polymorphism-draft.html' title='Kind polymorphism - a draft'/><author><name>g</name><uri>http://www.blogger.com/profile/04686862403622560424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3679812208800765969.post-2042545590888158464</id><published>2010-09-01T14:44:00.001-07:00</published><updated>2010-09-02T11:04:42.608-07:00</updated><title type='text'>Algorithms and functions</title><content type='html'>Consider the following two functions:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;f :: () -&gt; ()&lt;br /&gt;f = const ()&lt;br /&gt;&lt;br /&gt;g :: () -&gt; ()&lt;br /&gt;g = id&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Is there a way to write a function that tells them apart? Given an infinite loop, first will stop and the second will hang. But you can do better, give an exception and check if it was thrown:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;data TestException = TestException deriving (Show, Typeable)&lt;br /&gt;&lt;br /&gt;instance Exception TestException&lt;br /&gt;&lt;br /&gt;test :: (() -&gt; ()) -&gt; Bool&lt;br /&gt;test k = unsafePerformIO $ catch (k (throw TestException) `seq` return True)&lt;br /&gt;                                 (\TestException -&gt; return False)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Is this a safe trick?&lt;br /&gt;&lt;br /&gt;On the one hand, it looks rather innocently: a function is given some box, and if it opens it, it's caught red-handed. Such function would hang given infinite loop. A function that doesn't touch the box, yet finishes, is &lt;span style="font-family:courier new;"&gt;const ()&lt;/span&gt;. Such 'test' is a nice feature to have.&lt;br /&gt;&lt;br /&gt;On the other hand, something is wrong, since &lt;span style="font-family:courier new;"&gt;f&lt;/span&gt; is more defined than &lt;span style="font-family:courier new;"&gt;g&lt;/span&gt;, and &lt;span style="font-family:courier new;"&gt;test f&lt;/span&gt; is not at least as defined as &lt;span style="font-family:courier new;"&gt;test g&lt;/span&gt;. This contradicts monotonicity. By giving two exceptions to (+), you can check which argument is evaluated first:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;throw A + throw B&lt;/pre&gt;&lt;br /&gt;That means &lt;span style="font-family:courier new;"&gt;flip (+)&lt;/span&gt; is not the same as &lt;span style="font-family:courier new;"&gt;(+)&lt;/span&gt;. Addition is not commutative!&lt;br /&gt;&lt;br /&gt;Which of these points is correct?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The representation of a-&gt;b&lt;/b&gt;&lt;br /&gt;Internally, the (-&gt;) type is a list of instructions - force a thunk, case, perform a primitive instruction like adding integers. In other words, it's an algorithm. You could conceivably write an algebraic datatype that encompassed all those options.&lt;br /&gt;&lt;pre&gt;data Instruction a b = Force Thunk | Return Value...&lt;br /&gt;type Algorithm a b = [Instruction a b]&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Haskell has an evaluator that takes an algorithm and runs it step by step.&lt;br /&gt;&lt;pre&gt;($) :: Algorithm a b -&gt; a -&gt; b&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Having access to internal source code of an algorithm, you can write a "debugger" that stops if the function forces its argument. In a sense, this is what the function &lt;span style="font-family:courier new;"&gt;test&lt;/span&gt; is doing.&lt;br /&gt;&lt;br /&gt;Lazy IO uses this trick. When a thunk is forced evaluation is stopped momentarily, and IO is performed.&lt;br /&gt;&lt;br /&gt;Still, the denotational semantics argument seems disturbing.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The distinction&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The solution to the dilemma is:&lt;br /&gt;&lt;br /&gt;There are two different ways of interpreting values of type a -&gt; b.&lt;ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;functions&lt;/strong&gt; that assign a value of b to each value of a.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;algorithms&lt;/strong&gt; that are recipes how to turn a into b.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;In Haskell, the function view is used, but in this post I'll use both to illustrate differences. I'll call the algorithm view "operational" and function view "denotational".&lt;br /&gt;&lt;br /&gt;Representing algorithms is possible using ADT, as you seen above. Functions are represented using algorithms:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;data Function a b = Function (Algorithm a b)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You can turn an algorithm into a function:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;evaluate :: Algorithm a b -&gt; Function a b&lt;br /&gt;evaluate = Function&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;but the reverse conversion is ill-defined - one function has many representations. &lt;span style="font-family:courier new;"&gt;evaluate&lt;/span&gt; turns an algorithm into a "black box".&lt;br /&gt;&lt;br /&gt;Think about rational numbers. You represent them as pairs of integers, even though a rational number is not a pair. Then, you write operations like addition, which don't break 'internal consistency'. Not every operation on pairs can be lifted to operation on rationals. Different pairs may represent same rationals. It's the same with functions stored as algorithms.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Questions:&lt;/b&gt;&lt;br /&gt;The questions focus on differences between algorithms and functions.&lt;br /&gt;&lt;br /&gt;1. Can you compare values of type a -&gt; b for equality?&lt;br /&gt;&lt;a href='javascript:toggle("sol1a")'&gt;Answer&lt;/a&gt;&lt;br /&gt;&lt;div id="sol1a" style="display:none"&gt;You can compare algorithms, since they are lists of instructions. You cannot in general compare functions because of the halting problem.&lt;br /&gt;&lt;br /&gt;For example, the following two are different algorithms:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;mergesort :: Ord a =&gt; [a] -&gt; [a]&lt;br /&gt;insertionsort :: Ord a =&gt; [a] -&gt; [a]&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;But they are the same functions: &lt;span style="font-family:courier new;"&gt;evaluate mergesort&lt;/span&gt; is the same as &lt;span style="font-family:courier new;"&gt;evaluate insertionsort&lt;/span&gt;. In denotational view asymptotic complexity is discounted.&lt;br /&gt;&lt;br /&gt;In operational view, &lt;span style="font-family:courier new;"&gt;\x -&gt; 4&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;\x -&gt; 2+2&lt;/span&gt; are two different values. Equational reasoning is not allowed, since there's "quoting" after lambda.&lt;br /&gt;&lt;/div&gt;&lt;hr/&gt;&lt;br /&gt;2. How would you show an algorithm? A function?&lt;br /&gt;&lt;a href='javascript:toggle("sol2a")'&gt;Answer&lt;/a&gt;&lt;br /&gt;&lt;div id="sol2a" style="display:none"&gt;You can show an algorithm showing its source code. You can show a function by allowing the user to interactively change the argument, and displaying the result in response.&lt;br /&gt;&lt;/div&gt;&lt;hr/&gt;&lt;br /&gt;3. How would you read an algorithm? A function?&lt;br /&gt;&lt;a href='javascript:toggle("sol3a")'&gt;Answer&lt;/a&gt;&lt;br /&gt;&lt;div id="sol3a" style="display:none"&gt;To read an algorithm, read its source code. To read a function, the user must act as an oracle, giving the result of the function when asked.&lt;br /&gt;&lt;/div&gt;&lt;hr/&gt;&lt;br /&gt;4. What abstract models of computation correspond to algorithms and functions?&lt;br /&gt;&lt;a href='javascript:toggle("sol4a")'&gt;Answer&lt;/a&gt;&lt;br /&gt;&lt;div id="sol4a" style="display:none"&gt;Turing machines and lambda calculus, respectively.&lt;br /&gt;&lt;/div&gt;&lt;hr/&gt;&lt;br /&gt;5. How does semantic order on values a -&gt; b look like?&lt;br /&gt;&lt;a href='javascript:toggle("sol5a")'&gt;Answer&lt;/a&gt;&lt;br /&gt;&lt;div id="sol5a" style="display:none"&gt;Denotationally, f&gt;=g means that for all x, f(x)&gt;=g(x).&lt;br /&gt;&lt;br /&gt;Operationally, algorithms are only "source codes" and are ordered discretely, as integers:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_A5ZPqPvNJqM/S-AxN4nKD0I/AAAAAAAAAGs/F8vKNwtSiy4/s1600/7.jpg"&gt;&lt;img margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 67px;" src="http://4.bp.blogspot.com/_A5ZPqPvNJqM/S-AxN4nKD0I/AAAAAAAAAGs/F8vKNwtSiy4/s400/7.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5467424062232465218" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;That's why the &lt;span style="font-family:courier new;"&gt;test&lt;/span&gt; function from beginning is correct from the operational view. It's not true that algorithm &lt;span style="font-family:courier new;"&gt;f&lt;/span&gt; is more defined than algorithm &lt;span style="font-family:courier new;"&gt;g&lt;/span&gt;.&lt;br /&gt;&lt;/div&gt;&lt;hr/&gt;&lt;br /&gt;&lt;br /&gt;6. Is the following function&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;f :: (() -&gt; ()) -&gt; Bool&lt;br /&gt;"f g = [return True if evaluation of g () halts within 100 evaluation steps]"&lt;/pre&gt;&lt;br /&gt;well-defined?&lt;br /&gt;&lt;br /&gt;&lt;a href='javascript:toggle("sol6a")'&gt;Answer&lt;/a&gt;&lt;br /&gt;&lt;div id="sol6a" style="display:none"&gt;It is correct if you fix operational semantics and consider the argument to be an algorithm. It falls under "debugging" category. However, since implementations of the same function may run for different amounts of time, it doesn't make sense in denotational view.&lt;br /&gt;&lt;/div&gt;&lt;hr/&gt;&lt;br /&gt;7. What about this?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;lub :: (Bool -&gt; ()) -&gt; ()&lt;br /&gt;lub f = [return () if evaluation of f False or f True halts]&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href='javascript:toggle("sol7a")'&gt;Answer&lt;/a&gt;&lt;br /&gt;&lt;div id="sol7a" style="display:none"&gt;It makes sense in algorithm view, since you can run f False and f True in parallel, interleaving steps. But as it turns out, this is a rare case where a function makes sense in denotational semantics. See &lt;a href="http://hackage.haskell.org/package/lub"&gt;lub&lt;/a&gt; package.&lt;br /&gt;&lt;/div&gt;&lt;hr/&gt;&lt;br /&gt;8. Since a-&gt;b in Haskell is seen as function type, not algorithm type, anything dependent of "internals" is ambiguous. How does Haskell deal with it?&lt;br /&gt;&lt;br /&gt;&lt;a href='javascript:toggle("sol8a")'&gt;Answer&lt;/a&gt;&lt;br /&gt;&lt;div id="sol8a" style="display:none"&gt;By using the IO monad.&lt;br /&gt;&lt;br /&gt;For example, catching exceptions is allowed only in IO, since they can be used to inspect evaluation order. Another example is:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Control.Concurrent.mergeIO :: [a] -&gt; [a] -&gt; IO [a]&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You can deem lazy I/O as safe, if you take the 'algorithm' view. In the denotational view, &lt;a href="http://www.haskell.org/pipermail/haskell/2009-March/021064.html"&gt;lazy IO doesn't make sense&lt;/a&gt; unless you consider IO as nondeterministic.&lt;br /&gt;&lt;br /&gt;In my opinion this is not a good approach, and it might be better if Haskell had separate types for computations and values. (A computation can be thought as an algorithm returning a value. For example, 2+2 and 4 are two different computations.)&lt;br /&gt;&lt;/div&gt;&lt;hr/&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Summary&lt;/b&gt;&lt;br /&gt;In most languages, 'functions' are algorithms. In Haskell, the emphasis is on functions as in mathematics and referential transparency. &lt;br /&gt;&lt;br /&gt;Since Haskell is running on a computer, operational semantics (algorithms) describe how things work on the lower level and you can't do away with them. Things like "debugging", "unsafePerformIO", "measuring time/space complexity of a function", "order of evaluation" are relevant to operational semantics and break the abstraction. Things like "referential transparency" or "functional reactive programming" are valid for functions.&lt;br /&gt;&lt;br /&gt;I think this is what makes Haskell different from imperative languages. FP is about functions, not algorithms. This has advantages, like better support for composability - and disadvantages, like more difficult time/space reasoning.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3679812208800765969-2042545590888158464?l=monoidal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://monoidal.blogspot.com/feeds/2042545590888158464/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3679812208800765969&amp;postID=2042545590888158464' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3679812208800765969/posts/default/2042545590888158464'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3679812208800765969/posts/default/2042545590888158464'/><link rel='alternate' type='text/html' href='http://monoidal.blogspot.com/2010/09/algorithms-and-functions.html' title='Algorithms and functions'/><author><name>g</name><uri>http://www.blogger.com/profile/04686862403622560424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_A5ZPqPvNJqM/S-AxN4nKD0I/AAAAAAAAAGs/F8vKNwtSiy4/s72-c/7.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3679812208800765969.post-5039147534361793299</id><published>2010-07-29T08:51:00.001-07:00</published><updated>2010-07-29T10:40:34.609-07:00</updated><title type='text'>The universal space</title><content type='html'>Take (or imagine) a blank sheet of paper. This is a plane. You can put points and vectors on it. A vector connects two points, but it is "movable": if you can translate one vector into another, they are deemed equal. A vector doesn't really have a beginning - you can position it wherever you want.&lt;br /&gt;&lt;br /&gt;In this setting, some operations make sense, like&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;vector + point = point:&lt;br /&gt;Position the vector at a point, and its end will be the result.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;point - point = vector:&lt;br /&gt;Join the points to get a vector from A to B. (It's inverse of vector + point = point.)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;vector + vector = vector:&lt;br /&gt;Put the beginning of one vector to the end of the second.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;But some don't, like adding two points, or subtracting vector - point. With added origin, you can do anything using coordinates, as in (2,1) + (3,0) = (5,1). In fact, with given origin you can consider every point as a vector from the origin. But without it, it's like physical motion - you cannot tell if something is moving without a frame of reference.&lt;br /&gt;&lt;br /&gt;Although addition point + point doesn't make sense, (point + point) / 2 should - it's middle between the points. 0.2 point + 0.8 point is somewhere in the 4/5 of the segment. This is known as "affine combination".&lt;br /&gt;&lt;br /&gt;An expression like vector + point - point can be computed in two different ways: (vector + point) - point and vector + (point - point) and it turns out the result will be the same. There must be some structure here.&lt;br /&gt;&lt;br /&gt;Define mass of a vector as 0, and mass of point as 1. Then,&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;vector + point = point: 0 + 1 = 1&lt;/li&gt;&lt;br /&gt;&lt;li&gt;point - point = vector: 1 - 1 = 0&lt;/li&gt;&lt;br /&gt;&lt;li&gt;vector + vector = vector: 0 + 0 = 0&lt;/li&gt;&lt;br /&gt;&lt;li&gt;(point + point) / 2 = point: (1+1) / 2 = 1&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;In fact you can enlarge the space. Define an object to be either a vector with mass 0, or a pair (p,m) which is a point p with a nonzero mass m. I'll write a point as m*p. Then multiplication streches a vector, or changes a point's mass: a*(m*p) = (a*m)*p. Addition is done with:&lt;br /&gt;&lt;br /&gt;&lt;div class="latex"&gt;m p + v = m (p + \frac{v}{m})&lt;/div&gt; - translation&lt;br /&gt;&lt;br /&gt;&lt;div class="latex"&gt;m_{1}p_{1} + m_{2}p_{2} = (m_{1}+m_{2}) (\frac{m_{1}}{m_{1}+m_{2}} p_{1} + \frac{m_{2}}{m_{1}+m_{2}} p_{2})&lt;/div&gt; - weighted mean of points&lt;br /&gt;&lt;br /&gt;&lt;div class="latex"&gt;m_{1}p_{1} - m_{1} p_{2} = m_{1} (p_{1} - p_2})&lt;/div&gt; - a vector joining two points&lt;br /&gt;&lt;br /&gt;In this space, points and vectors are equal partners, and anything can be added and multiplied by a number. It's a vector space with dimension one more than the original.&lt;br /&gt;&lt;br /&gt;In the original space, you assign a meaning to a sum like 0.2a + 0.8b, but not to the summands. In this space, summands make sense and 0.2a + 0.8b is really a sum of 0.2a and 0.8b.&lt;br /&gt;&lt;br /&gt;In mathematical terms, this is an assignment of a vector space to every affine space. This construction is known as the universal space. Now, vector spaces and affine spaces have their own meaning of functions. A linear map respects linear combinations: f(cx+dy) = c f(x)+d f(y). An affine map is something that respects affine combinations: f(cx+dy) = cf(x)+ df(y), where c+d=1. It's easy to present a linear map using a matrix. How to present an affine map? The answer is, given affine map, you can extend it to a linear map between universal spaces by f(m*p)=m*f(p) for all m. And that &lt;a href="http://en.wikipedia.org/wiki/Affine_map#Representation"&gt;gives&lt;/a&gt; a matrix. &lt;br /&gt;&lt;br /&gt;For category theory lovers, this construction is the left adjoint of a functor that assigns an affine space to a vector space by forgetting the origin.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3679812208800765969-5039147534361793299?l=monoidal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://monoidal.blogspot.com/feeds/5039147534361793299/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3679812208800765969&amp;postID=5039147534361793299' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3679812208800765969/posts/default/5039147534361793299'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3679812208800765969/posts/default/5039147534361793299'/><link rel='alternate' type='text/html' href='http://monoidal.blogspot.com/2010/07/universal-space.html' title='The universal space'/><author><name>g</name><uri>http://www.blogger.com/profile/04686862403622560424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3679812208800765969.post-3446503915946754235</id><published>2010-07-26T16:49:00.000-07:00</published><updated>2010-07-28T11:31:13.795-07:00</updated><title type='text'>Kind polymorphism in action</title><content type='html'>&lt;a href="http://www.cs.uu.nl/wiki/UHC"&gt;Ultrecht Haskell Compiler&lt;/a&gt; is an experimental Haskell compiler that supports polymorphism on the kind level. This means that in&lt;br /&gt;&lt;pre&gt;data Eq a b = Eq (forall f. f a -&gt; f b)&lt;/pre&gt;&lt;br /&gt;Eq is given kind&lt;br /&gt;&lt;pre&gt;Eq :: forall a . a -&gt; a -&gt; *&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and both Eq Integer Char and Eq [] Maybe are valid types.&lt;br /&gt;&lt;br /&gt;Using kind polymorphism, it is possible to write sigfpe's &lt;a href="http://blog.sigfpe.com/2008/11/from-monoids-to-monads.html"&gt;From monoids to monads&lt;/a&gt; using a single type class.&lt;br /&gt;&lt;br /&gt;To talk about monoids, you need a category (mor), multiplication (mul) and a unit.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;class Monoid mor mul unit m where&lt;br /&gt;  one :: mor unit m&lt;br /&gt;  mult :: mor (mul m m) m&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;With mor being (-&gt;), mul being (,), unit being () this is a normal monoid (one :: () -&gt; m and mult :: (m,m) -&gt; m.). For example:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;instance Monoid (-&gt;) (,) () Integer where&lt;br /&gt;  one () = 1&lt;br /&gt;  mult = uncurry (*)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now, instead of functions, there will be natural transformations; instead of (,) there will be functor composition; instead of unit there will be identity functor.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;data Nat f g = Nat (forall x. f x -&gt; g x)&lt;br /&gt;data Comp f g x = Comp (f (g x))&lt;br /&gt;data Id x = Id x&lt;br /&gt;Nat :: (* -&gt; *) -&gt; (* -&gt; *) -&gt; *&lt;br /&gt;Comp :: (* -&gt; *) -&gt; (* -&gt; *) -&gt; * -&gt; *&lt;br /&gt;Id :: * -&gt; *&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And here is the list monad. Notice kinds are different than in the previous case, but it is still an instance of the same type class.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;instance Monoid Nat Comp Id [] where&lt;br /&gt;  one = Nat $ \(Id x) -&gt; [x]              -- one :: Nat Id []&lt;br /&gt;  mult = Nat $ \(Comp x) -&gt; concat x      -- mult :: Nat (Comp [] []) []&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So, monads are really monoids in category of endofunctors.&lt;br /&gt;&lt;br /&gt;If you invert the arrows, you get a comonad. Here's the product comonad.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;data CoNat f g = CoNat (forall x. g x -&gt; f x)&lt;br /&gt;data CoComp f g x = CoComp (g (f x))&lt;br /&gt;CoNat :: (* -&gt; *) -&gt; (* -&gt; *) -&gt; *&lt;br /&gt;CoComp :: (* -&gt; *) -&gt; (* -&gt; *) -&gt; * -&gt; *&lt;br /&gt;&lt;br /&gt;data Product w a = Product w a&lt;br /&gt;&lt;br /&gt;instance Monoid CoNat CoComp Id (Product w) where&lt;br /&gt;  one = CoNat $ \(Product a b) -&gt; Id b&lt;br /&gt;  mult = CoNat $ \(Product a b) -&gt; CoComp $ Product a (Product a b)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Question: what are kinds of mor, mul, unit and m in the Monoid type class definition?&lt;br /&gt;&lt;br /&gt;There's a small lie here: monads require also a liftM/fmap function. Not all Haskell types of * -&gt; * are functors, and I used that as a poor replacement.&lt;br /&gt;&lt;br /&gt;I didn't write monoid laws, which if translated happen to be monad laws. You're welcome to read sigfpe's original post. It's hard to write them generically since there's no access to fmap.&lt;br /&gt;&lt;br /&gt;The code is available on &lt;a href="http://hpaste.org/fastcgi/hpaste.fcgi/view?id=28248"&gt;hpaste&lt;/a&gt; and can be run in UHC.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3679812208800765969-3446503915946754235?l=monoidal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://monoidal.blogspot.com/feeds/3446503915946754235/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3679812208800765969&amp;postID=3446503915946754235' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3679812208800765969/posts/default/3446503915946754235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3679812208800765969/posts/default/3446503915946754235'/><link rel='alternate' type='text/html' href='http://monoidal.blogspot.com/2010/07/kind-polymorphism-in-action.html' title='Kind polymorphism in action'/><author><name>g</name><uri>http://www.blogger.com/profile/04686862403622560424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3679812208800765969.post-6268759169947256684</id><published>2010-05-04T08:04:00.001-07:00</published><updated>2010-05-07T13:34:32.905-07:00</updated><title type='text'>Denotational semantics</title><content type='html'>You're given diagrams of some Haskell types ordered by semantic order. Vertices are inhabitants of a datatype, and the lines point upwards, from less defined to more defined. (See &lt;a href="http://en.wikibooks.org/wiki/Haskell/Denotational_semantics"&gt;Wikibooks&lt;/a&gt; for an introduction and examples.) Your objective is to construct a type corresponding to the diagram, or show that is impossible.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I've done the first one - it is obviously Bool. Good luck!&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Diagram&lt;/td&gt;&lt;td&gt;Type&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_A5ZPqPvNJqM/S-AwIinHU6I/AAAAAAAAAF8/pxSRzhdp6Y0/s1600/1.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 67px;" src="http://4.bp.blogspot.com/_A5ZPqPvNJqM/S-AwIinHU6I/AAAAAAAAAF8/pxSRzhdp6Y0/s400/1.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5467422870915732386" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;pre&gt;Bool&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_A5ZPqPvNJqM/S-AwIxJnWfI/AAAAAAAAAGE/24KlQV2z0EY/s1600/2.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 112px;" src="http://1.bp.blogspot.com/_A5ZPqPvNJqM/S-AwIxJnWfI/AAAAAAAAAGE/24KlQV2z0EY/s400/2.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5467422874818533874" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a href='javascript:toggle("sol2")'&gt;Solution&lt;/a&gt;&lt;br /&gt;&lt;div id="sol2" style="display:none"&gt;&lt;br /&gt;&lt;pre&gt;data Three = X | Y | Z&lt;br /&gt;data Four = A | B | C | D&lt;br /&gt;data T = P | Q Three | R Four&lt;/pre&gt;&lt;br /&gt;Using this method you can define any finite tree.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_A5ZPqPvNJqM/S-R2JxY8duI/AAAAAAAAAIQ/bYeR2ZxLev4/s1600/2desc.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 243px; height: 172px;" src="http://2.bp.blogspot.com/_A5ZPqPvNJqM/S-R2JxY8duI/AAAAAAAAAIQ/bYeR2ZxLev4/s400/2desc.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5468625757783488226" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_A5ZPqPvNJqM/S-R2KGT7ZhI/AAAAAAAAAIY/NUfseSTyXrw/s1600/3.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 125px;" src="http://2.bp.blogspot.com/_A5ZPqPvNJqM/S-R2KGT7ZhI/AAAAAAAAAIY/NUfseSTyXrw/s400/3.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5468625763399591442" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a href='javascript:toggle("sol3")'&gt;Solution&lt;/a&gt;&lt;br /&gt;&lt;div id="sol3" style="display:none"&gt;&lt;br /&gt;&lt;pre&gt;data NaturalsUp = S NaturalsUp&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_A5ZPqPvNJqM/S-R2KXl7pXI/AAAAAAAAAIg/zdMNSV_aAoc/s1600/3desc.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 125px;" src="http://3.bp.blogspot.com/_A5ZPqPvNJqM/S-R2KXl7pXI/AAAAAAAAAIg/zdMNSV_aAoc/s400/3desc.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5468625768038507890" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_A5ZPqPvNJqM/S-R2KRlq5pI/AAAAAAAAAIo/ZPXj_fLJTxg/s1600/4.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 94px;" src="http://2.bp.blogspot.com/_A5ZPqPvNJqM/S-R2KRlq5pI/AAAAAAAAAIo/ZPXj_fLJTxg/s400/4.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5468625766426797714" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a href='javascript:toggle("sol4")'&gt;Solution&lt;/a&gt;&lt;br /&gt;&lt;div id="sol4" style="display:none"&gt;&lt;br /&gt;Impossible. There is no bottom element.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_A5ZPqPvNJqM/S-R2K-VDc5I/AAAAAAAAAIw/OCC5dqkBhGw/s1600/5.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 146px;" src="http://1.bp.blogspot.com/_A5ZPqPvNJqM/S-R2K-VDc5I/AAAAAAAAAIw/OCC5dqkBhGw/s400/5.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5468625778436699026" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a href='javascript:toggle("sol5")'&gt;Solution&lt;/a&gt;&lt;br /&gt;&lt;div id="sol5" style="display:none"&gt;&lt;br /&gt;&lt;pre&gt;type NaturalsDown = NaturalsUp -&gt; ()&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_A5ZPqPvNJqM/S-R3lIXD2UI/AAAAAAAAAJI/C39GGMwfXQs/s1600/5desc.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 146px;" src="http://2.bp.blogspot.com/_A5ZPqPvNJqM/S-R3lIXD2UI/AAAAAAAAAJI/C39GGMwfXQs/s400/5desc.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5468627327317694786" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_A5ZPqPvNJqM/S-R3k7xgXLI/AAAAAAAAAJA/3fCOFzru_v8/s1600/6.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 166px;" src="http://2.bp.blogspot.com/_A5ZPqPvNJqM/S-R3k7xgXLI/AAAAAAAAAJA/3fCOFzru_v8/s400/6.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5468627323938954418" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a href='javascript:toggle("sol6")'&gt;Solution&lt;/a&gt;&lt;br /&gt;&lt;div id="sol6" style="display:none"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;data Wrap = Wrap k&lt;br /&gt;type T = Wrap (Wrap (Maybe NaturalsUp)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_A5ZPqPvNJqM/S-AxN4nKD0I/AAAAAAAAAGs/F8vKNwtSiy4/s1600/7.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 67px;" src="http://4.bp.blogspot.com/_A5ZPqPvNJqM/S-AxN4nKD0I/AAAAAAAAAGs/F8vKNwtSiy4/s400/7.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5467424062232465218" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a href='javascript:toggle("sol7")'&gt;Solution&lt;/a&gt;&lt;br /&gt;&lt;div id="sol7" style="display:none"&gt;&lt;br /&gt;&lt;pre&gt;Integer&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_A5ZPqPvNJqM/S-AxOEGM8PI/AAAAAAAAAG0/9vccg9K4xMM/s1600/8.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 156px;" src="http://3.bp.blogspot.com/_A5ZPqPvNJqM/S-AxOEGM8PI/AAAAAAAAAG0/9vccg9K4xMM/s400/8.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5467424065315467506" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a href='javascript:toggle("sol8")'&gt;Solution&lt;/a&gt;&lt;br /&gt;&lt;div id="sol8" style="display:none"&gt;&lt;br /&gt;&lt;pre&gt;((),())&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_A5ZPqPvNJqM/S-AxOSDubiI/AAAAAAAAAG8/98HGUYX7x1E/s1600/9.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 155px;" src="http://2.bp.blogspot.com/_A5ZPqPvNJqM/S-AxOSDubiI/AAAAAAAAAG8/98HGUYX7x1E/s400/9.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5467424069063175714" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a href='javascript:toggle("sol9")'&gt;Solution&lt;/a&gt;&lt;br /&gt;&lt;div id="sol9" style="display:none"&gt;&lt;br /&gt;&lt;pre&gt;data T = L T | R T&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_A5ZPqPvNJqM/S-AxOongtJI/AAAAAAAAAHE/L1iIu9HctA0/s1600/10.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 155px;" src="http://1.bp.blogspot.com/_A5ZPqPvNJqM/S-AxOongtJI/AAAAAAAAAHE/L1iIu9HctA0/s400/10.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5467424075118851218" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a href='javascript:toggle("sol10")'&gt;Solution&lt;/a&gt;&lt;br /&gt;&lt;div id="sol10" style="display:none"&gt;&lt;br /&gt;Impossible. The type must form a complete partial order - you could carry the computation indefinitely long, and get the infinite path.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_A5ZPqPvNJqM/S-R3lX2GS0I/AAAAAAAAAJQ/37ZOCoeoo2w/s1600/11.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 154px;" src="http://2.bp.blogspot.com/_A5ZPqPvNJqM/S-R3lX2GS0I/AAAAAAAAAJQ/37ZOCoeoo2w/s400/11.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5468627331474410306" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a href='javascript:toggle("sol11")'&gt;Solution&lt;/a&gt;&lt;br /&gt;&lt;div id="sol11" style="display:none"&gt;&lt;br /&gt;&lt;pre&gt;data T1 = A T2 | B T2&lt;br /&gt;data T2 = C T1 | D T1 | E T1&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_A5ZPqPvNJqM/S-Axz2WsYUI/AAAAAAAAAHU/AAMctstNorc/s1600/12.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 32px;" src="http://2.bp.blogspot.com/_A5ZPqPvNJqM/S-Axz2WsYUI/AAAAAAAAAHU/AAMctstNorc/s400/12.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5467424714461569346" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a href='javascript:toggle("sol12")'&gt;Solution&lt;/a&gt;&lt;br /&gt;&lt;div id="sol12" style="display:none"&gt;&lt;br /&gt;&lt;pre&gt;data Void&lt;/pre&gt;&lt;br /&gt;An empty data type has no inhabitants other than bottom. It is used in &lt;a href="http://www.haskell.org/haskellwiki/Phantom_type"&gt;phantom types.&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_A5ZPqPvNJqM/S-Ax0GHEIqI/AAAAAAAAAHc/L6o4S4cAm1w/s1600/13.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 160px;" src="http://3.bp.blogspot.com/_A5ZPqPvNJqM/S-Ax0GHEIqI/AAAAAAAAAHc/L6o4S4cAm1w/s400/13.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5467424718690984610" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a href='javascript:toggle("sol13")'&gt;Solution&lt;/a&gt;&lt;br /&gt;&lt;div id="sol13" style="display:none"&gt;&lt;br /&gt;&lt;pre&gt;data Void&lt;br /&gt;data B k = B k deriving (Show)&lt;br /&gt;data T x = P x | A !(T (B x)) deriving (Show)&lt;br /&gt;type X = T Void&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The tree looks like:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_A5ZPqPvNJqM/S-Ax0rrRr_I/AAAAAAAAAHk/n4JOuRP3D28/s1600/13a.jpg"&gt;&lt;img style="display:block; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 311px; height: 186px;" src="http://2.bp.blogspot.com/_A5ZPqPvNJqM/S-Ax0rrRr_I/AAAAAAAAAHk/n4JOuRP3D28/s400/13a.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5467424728774979570" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The type system is quite expressive - for example, the depths could form only perfect squares.&lt;/div&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_A5ZPqPvNJqM/S-R3lnOgITI/AAAAAAAAAJY/qh1Qd_QZjAk/s1600/14.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 125px;" src="http://1.bp.blogspot.com/_A5ZPqPvNJqM/S-R3lnOgITI/AAAAAAAAAJY/qh1Qd_QZjAk/s400/14.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5468627335603298610" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;This is a variant of NaturalsDown and will require cheating a little. Create a module that will export a data type, and only a "&lt;a href="http://www.haskell.org/haskellwiki/Smart_constructors"&gt;smart constructor&lt;/a&gt;" that will equate undefined and const undefined.&lt;br /&gt;&lt;br /&gt;&lt;a href='javascript:toggle("sol14")'&gt;Solution&lt;/a&gt;&lt;br /&gt;&lt;div id="sol14" style="display:none"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;module M (Fun, Nat(..), create) where&lt;br /&gt;&lt;br /&gt;data Nat = Zero | S Nat&lt;br /&gt;newtype Fun = Fun (Nat -&gt; ())&lt;br /&gt;&lt;br /&gt;infinity = S infinity&lt;br /&gt;create :: (Nat -&gt; ()) -&gt; Fun&lt;br /&gt;create f = seq (f infinity) (Fun f)&lt;br /&gt;&lt;/pre&gt; Outside the module, you cannot create Fun (const undefined).&lt;/div&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Application&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;A great application of denotational semantics is doing &lt;a href="http://conal.net/blog/posts/exact-numeric-integration/"&gt;numerical integration&lt;/a&gt; exactly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3679812208800765969-6268759169947256684?l=monoidal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://monoidal.blogspot.com/feeds/6268759169947256684/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3679812208800765969&amp;postID=6268759169947256684' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3679812208800765969/posts/default/6268759169947256684'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3679812208800765969/posts/default/6268759169947256684'/><link rel='alternate' type='text/html' href='http://monoidal.blogspot.com/2010/05/denotational-semantics.html' title='Denotational semantics'/><author><name>g</name><uri>http://www.blogger.com/profile/04686862403622560424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_A5ZPqPvNJqM/S-AwIinHU6I/AAAAAAAAAF8/pxSRzhdp6Y0/s72-c/1.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3679812208800765969.post-85806845658944128</id><published>2010-04-26T06:39:00.001-07:00</published><updated>2010-04-27T03:57:20.696-07:00</updated><title type='text'>Conjugating verbs in Haskell</title><content type='html'>&lt;pre&gt;&lt;br /&gt;&gt; {-# LANGUAGE RecordWildCards #-}&lt;br /&gt;&gt; import Data.Maybe&lt;br /&gt;&gt; import Data.Default&lt;br /&gt;&gt; import Control.Monad.Writer hiding (First)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I'll show you an English verb conjugator. Although handling inflections is complex, the structure of the language can be expressed idiomatically, using a monad. You'll see that things like "perfect continuous" are really "perfect" on top of "continuous", in code.&lt;br /&gt;&lt;br /&gt;First, some boring code and auxiliary functions.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; data Tense = Past | Present | Future&lt;br /&gt;&gt; type Infinitive = String&lt;br /&gt;&gt; data Person = First | Second | Third&lt;br /&gt;&gt; -- plural in English is the same form as second person&lt;br /&gt;&lt;br /&gt;&gt; pastForms inf = fromMaybe (inf++"ed", inf++"ed") $&lt;br /&gt;&gt;                   lookup inf [("do", ("did", "done")),&lt;br /&gt;&gt;                               ("have", ("had", "had")),&lt;br /&gt;&gt;                               ("be", ("was", "been")),&lt;br /&gt;&gt;                               ("drive", ("drove", "driven")),&lt;br /&gt;&gt;                               ("build", ("built", "built"))]&lt;br /&gt;&lt;br /&gt;&gt; presentParticiple inf | last inf == 'e' &amp;&amp; inf /= "be" = init inf ++ "ing"&lt;br /&gt;&gt;                       | otherwise = inf ++ "ing"&lt;br /&gt;&lt;br /&gt;&gt; pastParticiple inf = snd $ pastForms inf&lt;br /&gt;&lt;br /&gt;&gt; conjugate1 :: Tense -&gt; Person -&gt; Infinitive -&gt; String&lt;br /&gt;&gt; conjugate1 Future p inf  = "will " ++ inf&lt;br /&gt;&gt; conjugate1 t      p "be" = case (t, p) of&lt;br /&gt;&gt;                              (Present, First) -&gt; "am"&lt;br /&gt;&gt;                              (Present, Second) -&gt; "are"&lt;br /&gt;&gt;                              (Present, Third) -&gt; "is"&lt;br /&gt;&gt;                              (Past, Second) -&gt; "were"&lt;br /&gt;&gt;                              (Past, _)      -&gt; "was"&lt;br /&gt;&lt;br /&gt;&gt; conjugate1 Past    p     inf = fst $ pastForms inf&lt;br /&gt;&gt; conjugate1 Present Third "have" = "has"&lt;br /&gt;&gt; conjugate1 Present Third "do" = "does"&lt;br /&gt;&gt; conjugate1 Present Third inf = inf ++ "s"&lt;br /&gt;&gt; conjugate1 Present _     inf = inf&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We can conjugate verbs in three tenses, and form participles. For example:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; test1 = conjugate1 Future First "drive"&lt;br /&gt;&gt; test2 = conjugate1 Present Third "phone"&lt;br /&gt;&gt; test3 = presentParticiple "have"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;Adding "perfect"&lt;/strong&gt;&lt;br /&gt;Now the fun begins.&lt;br /&gt;&lt;br /&gt;Exercise: Allow forming perfect tenses:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; conjugate2 :: Bool -&gt; Tense -&gt; Person -&gt; Infinitive -&gt; String&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;(For example, conjugate2 True Present Third "drive" should be "has driven")&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Solution:&lt;br /&gt;&lt;br /&gt;Perfect is "have" + past participle. You can express this directly:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; conjugate2 False tense person inf = conjugate1 tense person inf&lt;br /&gt;&gt; conjugate2 True tense person inf = conjugate1 tense person "have" ++ " " ++ pastParticiple inf&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Adding "continuous"&lt;/strong&gt;&lt;br /&gt;It will be downhill now.&lt;br /&gt;&lt;br /&gt;Exercise: Allow forming continuous tenses:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; conjugate3 :: Bool -&gt; Bool -&gt; Tense -&gt; Person -&gt; Infinitive -&gt; String&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;where the first parameter will be continuous or not. For example, conjugate3 True False Present Third "drive" should be "is driving".&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Solution:&lt;br /&gt;&lt;br /&gt;It's be + present participle.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; conjugate3 False perf tense person inf = conjugate2 perf tense person inf&lt;br /&gt;&gt; conjugate3 True perf tense person inf = conjugate2 perf tense person "be" ++ " " ++ presentParticiple inf&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This composes nicely:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; test4 = "he " ++ conjugate3 True True Present Third "drive"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;Adding passive voice&lt;/strong&gt;&lt;br /&gt;Exercise: Allow forming passive voice:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; conjugate4 :: Bool -&gt; Bool -&gt; Bool -&gt; Tense -&gt; Person -&gt; Infinitive -&gt; String&lt;br /&gt;&lt;br /&gt;&gt; test5 = "the house " ++ conjugate4 True True False Present Third "build"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Solution:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; conjugate4 False cont perf tense person inf = conjugate3 cont perf tense person inf&lt;br /&gt;&gt; conjugate4 True cont perf tense person inf = conjugate3 cont perf tense person "be" ++ " " ++ pastParticiple inf&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;Merging&lt;/strong&gt;&lt;br /&gt;conjugate2, conjugate3 and conjugate4 can be joined into a single function. &lt;br /&gt;Remembering all arguments in order and specifying them every time is problematic. This is described in Brent Yorgey's &lt;a href="http://byorgey.wordpress.com/2010/04/03/"&gt;Haskell anti-pattern - incremental ad-hoc parameter abstraction&lt;/a&gt;. Also there's a lot of repetition.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; conjugate5 :: Bool -&gt; Bool -&gt; Bool -&gt; Tense -&gt; Person -&gt; Infinitive -&gt; String&lt;br /&gt;&gt; conjugate5 True continuous perfect tense person inf =&lt;br /&gt;&gt;   conjugate5 False continuous perfect tense person "be" ++ " " ++ pastParticiple inf&lt;br /&gt;&gt; conjugate5 _ True perfect tense person inf =&lt;br /&gt;&gt;   conjugate5 False False perfect tense person "be" ++ " " ++ presentParticiple inf&lt;br /&gt;&gt; conjugate5 _ _ True tense person inf =&lt;br /&gt;&gt;   conjugate5 False False False tense person "have" ++ " " ++ pastParticiple inf&lt;br /&gt;&gt; conjugate5 _ _ _ tense person inf = conjugate1 tense person inf&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Using records&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; data ConjugateOptions = ConjugateOptions { passive :: Bool,&lt;br /&gt;&gt;                                            perfect :: Bool,&lt;br /&gt;&gt;                                            continuous :: Bool,&lt;br /&gt;&gt;                                            person :: Person,&lt;br /&gt;&gt;                                            tense :: Tense }&lt;br /&gt;&lt;br /&gt;&gt; instance Default ConjugateOptions where&lt;br /&gt;&gt;   def = ConjugateOptions False False False First Present&lt;br /&gt;&lt;br /&gt;&gt; conjugate6 :: ConjugateOptions -&gt; Infinitive -&gt; String&lt;br /&gt;&gt; conjugate6 (o@ConjugateOptions{ .. }) inf&lt;br /&gt;&gt;  | passive    = conjugate6 o { passive = False } "be" ++ " " ++ pastParticiple inf&lt;br /&gt;&gt;  | continuous = conjugate6 o { continuous = False } "be" ++ " " ++ presentParticiple inf&lt;br /&gt;&gt;  | perfect    = conjugate6 o { perfect = False } "have" ++ " " ++ pastParticiple inf&lt;br /&gt;&gt;  | otherwise  = conjugate1 tense person inf&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Much better - we can use it like&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; test6 = conjugate6 def { perfect=True } "paint"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Using the Writer monad&lt;/strong&gt;&lt;br /&gt;conjugate6 is doing recursion on some infinitive and adds "remaining part" to the end.  The Writer monad can express this.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; plumb :: Infinitive -&gt; (Infinitive -&gt; String) -&gt; Infinitive -&gt; Writer [String] Infinitive&lt;br /&gt;&gt; plumb aux participle inf = Writer (aux, [participle inf])&lt;br /&gt;&lt;br /&gt;&gt; passive' = plumb "be" pastParticiple&lt;br /&gt;&gt; continuous' = plumb "be" presentParticiple&lt;br /&gt;&gt; perfect' = plumb "have" pastParticiple&lt;br /&gt;&lt;br /&gt;&gt; conjugate7 :: Tense -&gt; Person -&gt; (Infinitive -&gt; Writer [String] Infinitive) -&gt; Infinitive -&gt; String&lt;br /&gt;&lt;br /&gt;&gt; conjugate7 tense person tr inf =&lt;br /&gt;&gt;   let (a,b) = runWriter (tr inf)&lt;br /&gt;&gt;   in  unwords $ (conjugate1 tense person a):(reverse b)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You can join those different "higher order verbs" using &gt;=&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; test7 = "he " ++ conjugate7 Past Third (continuous' &gt;=&gt; perfect') "paint"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and add new new ones instantly:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; learn = plumb "learn" ("to "++)&lt;br /&gt;&lt;br /&gt;&gt; test8 = "I " ++ conjugate7 Present First (learn &gt;=&gt; perfect') "love" ++ " Haskell"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Obviously there is a lot missing - inflections ("he go&lt;strong&gt;e&lt;/strong&gt;s", "he panic&lt;strong&gt;k&lt;/strong&gt;s"), irregular verbs, modal verbs, negation, "used to", "have something done", interrogative mood... It gets dirty then.&lt;br /&gt;&lt;br /&gt;You can write such conjugator in similar languages, like German.&lt;br /&gt;&lt;br /&gt;Haskell is a great language - imagine how would you write conjugate1 without pattern matching, or writing the plumbing in conjugate5 again, when Writer can do that for you.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3679812208800765969-85806845658944128?l=monoidal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://monoidal.blogspot.com/feeds/85806845658944128/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3679812208800765969&amp;postID=85806845658944128' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3679812208800765969/posts/default/85806845658944128'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3679812208800765969/posts/default/85806845658944128'/><link rel='alternate' type='text/html' href='http://monoidal.blogspot.com/2010/04/conjugating-verbs-in-haskell.html' title='Conjugating verbs in Haskell'/><author><name>g</name><uri>http://www.blogger.com/profile/04686862403622560424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3679812208800765969.post-7614787333981609701</id><published>2009-09-12T15:11:00.000-07:00</published><updated>2010-07-29T10:06:01.000-07:00</updated><title type='text'>Balanced brackets, finite sets and ordinal numbers</title><content type='html'>&lt;pre&gt;&lt;br /&gt;import Data.List&lt;br /&gt;import Data.Set as Set&lt;br /&gt;import Data.MultiSet as MultiSet  -- not required&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Balanced brackets&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://en.wikipedia.org/wiki/Dyck%20language"&gt;Dyck language&lt;/a&gt; is the set of correctly parenthesised strings, like "(()(()()))".&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;data Dyck = Dyck [Dyck]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you disregard the type constructor, an inhabitant looks like [[], [[], []]]. This type represents rooted trees. A rooted tree is a list of rooted trees. To convert a list of rooted trees to a rooted tree, you add the root. To convert back, you remove it.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_A5ZPqPvNJqM/SqFUpaVv7rI/AAAAAAAAABg/t8vYDUxIYnY/s1600-h/vvv.GIF"&gt;&lt;img style="display:block; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 100px;" src="http://4.bp.blogspot.com/_A5ZPqPvNJqM/SqFUpaVv7rI/AAAAAAAAABg/t8vYDUxIYnY/s400/vvv.GIF" border="0" alt=""id="BLOGGER_PHOTO_ID_5377672500478996146" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Traversing the tree gives us the string:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;string (Dyck x) = "(" ++ concatMap string x ++ ")"&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To be honest, we're missing strings like ()() and the real Dyck type is [Dyck]. But it isn't important since these types are isomorphic as the picture above shows.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Hereditarily finite sets&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;If we use sets instead of lists, then we get &lt;a href="http://en.wikipedia.org/wiki/Hereditarily_finite_set"&gt;hereditarily finite sets&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;data HFS = HFS (Set HFS)&lt;br /&gt;&lt;br /&gt;instance Eq HFS where&lt;br /&gt;  (==) (HFS x) (HFS y) = x == y&lt;br /&gt;&lt;br /&gt;instance Ord HFS where&lt;br /&gt;  compare (HFS x) (HFS y) = compare x y&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I was a bit surprised this works - to talk about Set HFS you have to implement comparision for HFS (since sets in Data.Set are binary search trees inside), but to implement comparision for HFS you have to define HFS first. Mutual recursion.&lt;br /&gt;&lt;br /&gt;Here are &lt;span class="latex"&gt;A=\{\emptyset\}&lt;/span&gt; and &lt;span class="latex"&gt;B=\{\emptyset, \{\emptyset\}\}&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;hfs = HFS . Set.fromList&lt;br /&gt;&lt;br /&gt;setA = hfs [hfs []]&lt;br /&gt;setB = hfs [hfs [], setA]&lt;br /&gt;&lt;br /&gt;-- Every natural number can be written in binary:&lt;br /&gt;data Binary = Natural -&gt; Bool&lt;br /&gt;-- We can write the exponents in binary too:&lt;br /&gt;data Binary = Binary -&gt; Bool&lt;br /&gt;-- And, since a function into Bool represents some set,&lt;br /&gt;data Binary = Set Binary&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This is the same as the equation for HFS. To convert, recursively change a number to the set of exponents: 15 = {0,1,2,3} = {{},{0},{1},{0,1}} = {{}, {{}}, {{0}}, {{},{0}}} = {{}, {{}}, {{{}}}, {{},{{}}}}. It turns out there's a &lt;a href="http://logic.cse.unt.edu/tarau/research/2008/fSET.pdf"&gt;paper&lt;/a&gt; on this subject.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Ordinal numbers&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Here's another example. If you don't know &lt;a href="http://en.wikipedia.org/wiki/Ordinal_number"&gt;ordinal numbers&lt;/a&gt; skip this paragraph. I'll talk only about ordinals lesser than &lt;span class="latex"&gt;\epsilon_{0}&lt;/span&gt;. They can be written in the form&lt;br /&gt;&lt;br /&gt;&lt;span class="latex"&gt;\omega^{a_1}+\dots+\omega^{a_n}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;where &lt;span class="latex"&gt;a_i&lt;/span&gt; is a nonincreasing sequence of ordinal numbers. These &lt;span class="latex"&gt;a_i&lt;/span&gt; may be written recursively in that form too, and this recursion will always stop at some point. You can put coefficients after each &lt;span class="latex"&gt;\omega^{a_i}&lt;/span&gt; and require that the sequence is decreasing. This looks very similar to previous examples.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;data ON = ON (MultiSet ON) -- (small) ordinal&lt;br /&gt;&lt;br /&gt;instance Eq ON where&lt;br /&gt;  (==) (ON x) (ON y) = x == y&lt;br /&gt;&lt;br /&gt;instance Ord ON where&lt;br /&gt;   compare (ON x) (ON y) = compare x y&lt;br /&gt;&lt;br /&gt;on = ON . MultiSet.fromList&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you don't have multisets installed (cabal install multiset), you may use lists instead and think of them as multisets. Just be careful to always put the items on the list in nonincreasing order.&lt;br /&gt;&lt;br /&gt;on [] is the empty sum - 0&lt;br /&gt;on [on []] is &lt;span class="latex"&gt;\omega^0=1&lt;/span&gt;&lt;br /&gt;on [on [on []]] is &lt;span class="latex"&gt;\omega^1=\omega&lt;/span&gt;&lt;br /&gt;on [on [on []],on []] is &lt;span class="latex"&gt;\omega+1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It is interesting that the ordering given by instance Ord is &lt;i&gt;exactly&lt;/i&gt; the standard ordering used in mathematics to compare ordinals. (It doesn't matter if you use multisets or sorted lists.) We got it out of nothing. Some other operations are also nicely implemented. The function &lt;span class="latex"&gt;\omega^x&lt;/span&gt; is simply f x = on [x]. The &lt;a href="http://en.wikipedia.org/wiki/Ordinal_arithmetic#Natural_operations"&gt;natural sum&lt;/a&gt; is sum of multisets (or merging of sorted lists). Normal addition isn't hard to write too.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Natural numbers&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Peano's natural numbers can be written as&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;data Nat = Succ Nat | Zero&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;or&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;data Nat = Nat (Maybe Nat)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The common pattern&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;What we have done above was finding a type X such that X=F(X) for some type constructor F (lists, sets, multisets, Maybe). This is the fixed point of F!&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;data Y f = Y (f (Y f))&lt;br /&gt;a = Y [Y [], Y [Y [], Y []]]&lt;br /&gt;&lt;br /&gt;ghci&gt; :t a&lt;br /&gt;a :: Y []&lt;br /&gt;ghci&gt; :k Y&lt;br /&gt;Y :: (* -&gt; *) -&gt; *&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It works. However, we can't show it (deriving (Show) won't help). &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Problem:&lt;/b&gt; Write an instance of Show. My solution is a workaround.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Solution:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;I do hope you tried and convinced yourself that something like&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;instance (Show (f a), Show a) =&gt; Show (Y f) where&lt;br /&gt;  show x = "Y " ++ (show x)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;or similar won't work. What we want is, in pseudocode:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;instance (forall a. Show a =&gt; Show (f a)) =&gt; Show (Y f) where&lt;br /&gt;  show x = "Y " ++ (show x)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In other words we require that f is a type constructor that conveys showability: if x is showable, then f x is showable too. I made a separate type class for such f.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Show' f where&lt;br /&gt;  show' :: (Show a) =&gt; f a -&gt; String&lt;br /&gt;&lt;br /&gt;instance Show' [] where&lt;br /&gt;  show' = show&lt;br /&gt;&lt;br /&gt;instance Show' Set where&lt;br /&gt;  show' = show&lt;br /&gt;&lt;br /&gt;instance Show' Multiset where&lt;br /&gt;  show' = show&lt;br /&gt;&lt;br /&gt;instance Show' f =&gt; Show (Y f) where&lt;br /&gt;  show (Y x) = "Y " ++ (show' x)&lt;br /&gt;&lt;br /&gt;ghci&gt; a&lt;br /&gt;Y [Y [],Y [Y [],Y []]]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Much better solutions are given in comments.&lt;br /&gt;&lt;br /&gt;The same boilerplate can be used for Eq and Ord to get two last examples as Y Set and Y Multiset. The instance of Ord gives you lexicographic order on the words in Dyck language (Y []), ordering of natural numbers written in binary (Y Set), ordering of natural numbers in unary (Y Maybe), and the normal ordering of ordinals (Y Multiset).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Exercise:&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;data H a = H (Maybe (Integer, a))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What is Y H? Write functions &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;convert :: that_type -&gt; Y H&lt;br /&gt;convert2 :: Y H -&gt; that_type&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you're stuck, try to construct some value of type Y H.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Solution:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Our fixed point equation is t = Maybe (Integer, t). I discussed this &lt;a href="http://monoidal.blogspot.com/2009/08/some-thoughts-and-exercises-on-folding.html"&gt;last time&lt;/a&gt;: these are lists. The conversion functions we are looking for are fold and unfold. I'll write another version of foldr I mentioned previously:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;foldr2 :: (Maybe (a,b) -&gt; b) -&gt; [a] -&gt; b&lt;br /&gt;foldr2 f = foldr (curry (f . Just)) (f Nothing)&lt;br /&gt;&lt;br /&gt;convert :: Y Helper -&gt; [Integer]&lt;br /&gt;convert2 :: [Integer] -&gt; Y Helper&lt;br /&gt;&lt;br /&gt;convert = unfoldr (\(Y (H x)) -&gt; x)&lt;br /&gt;convert2 = foldr2 (Y . H)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Many other recursive types like binary trees or infinite streams can be treated similarily.&lt;br /&gt;&lt;br /&gt;I ought to add infinite lists are lurking here. Our balanced brackets type has other inhabitants, like [[],[],...] or [[[...]]]. You shouldn't worry about that. First, we don't have to use all values of the type: as long as we're careful, they won't show up unexpectedly and you may regard the type as the type of finite lists. Second, you can enforce that with strictness. Third and most important point, infinite lists appear quite naturally and they do have applications.  I'll give an example later.&lt;br /&gt;&lt;br /&gt;[Update: expanded on the hereditarily finite sets. Thanks to Ryan Ingram and Edward Kmett for great solutions of Show (Y f).]&lt;br /&gt;&lt;br /&gt;[Update 17 Sep: I've found a &lt;a href="http://logic.csci.unt.edu/tarau/research/2009/fISO.pdf"&gt;paper&lt;/a&gt; (7 MB) covering very much of what I said. Haven't read it yet, but looks very promising.]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3679812208800765969-7614787333981609701?l=monoidal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://monoidal.blogspot.com/feeds/7614787333981609701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3679812208800765969&amp;postID=7614787333981609701' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3679812208800765969/posts/default/7614787333981609701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3679812208800765969/posts/default/7614787333981609701'/><link rel='alternate' type='text/html' href='http://monoidal.blogspot.com/2009/09/balanced-brackets-finite-sets-and.html' title='Balanced brackets, finite sets and ordinal numbers'/><author><name>g</name><uri>http://www.blogger.com/profile/04686862403622560424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_A5ZPqPvNJqM/SqFUpaVv7rI/AAAAAAAAABg/t8vYDUxIYnY/s72-c/vvv.GIF' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3679812208800765969.post-5062036139335198993</id><published>2009-08-22T09:36:00.000-07:00</published><updated>2010-04-26T06:51:04.149-07:00</updated><title type='text'>Some thoughts and exercises on folding</title><content type='html'>I assume you know what are foldl and foldr and have basic experience with them - you know how to express functions like sum, maximum using these folds. &lt;a href="http://cale.yi.org/index.php/Fold_Diagrams"&gt;Here&lt;/a&gt; are some very nice diagrams showing fold and related functions.&lt;br /&gt;&lt;br /&gt;Warmup exercise:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;compose :: [a -&gt; a] -&gt; a -&gt; a&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;compose [f1, f2, ..., fn] = f1 . f2 . ... . fn&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Write &lt;span style="font-family:courier new;"&gt;map&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;compose&lt;/span&gt; using &lt;span style="font-family:courier new;"&gt;foldr&lt;/span&gt;. Write &lt;span style="font-family:courier new;"&gt;foldr&lt;/span&gt; using &lt;span style="font-family:courier new;"&gt;map&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;compose&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Solution at the end.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Automata&lt;/span&gt;&lt;br /&gt;A finite automaton is some device that has finitely many states (finite memory), reads a string, letter by letter, and changes its state according to some fixed transition rules. For example, it can remember if the number of a's was even or odd - it toggles a single bit after each 'a'. Here's an automaton that checks if the whole word is built of 'x' and 'y' only:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;aut = foldl (\state a -&gt; state &amp;amp;&amp;amp; (a == 'x' || a == 'y')) True&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Automata are really doing foldl. In this case we could have written this more easily using &lt;span style="font-family:courier new;"&gt;all&lt;/span&gt;, but in general the behaviour can be quite complex.&lt;br /&gt;&lt;br /&gt;Exercise:&lt;br /&gt;&lt;br /&gt;I described a deterministic automaton - it always worked in the same way.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;deterministic :: (a -&gt; b -&gt; a) -&gt; a -&gt; [b] -&gt; a&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;deterministic = foldl&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now, we have a nondeterministic one - it can choose from some list of possible states and go on. Return all possible states the automaton could finish with.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;nondeterministic :: (a -&gt; b -&gt; [a]) -&gt; a -&gt; [b] -&gt; [a]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Don't worry about removing duplicates.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Solution:&lt;br /&gt;&lt;br /&gt;You can regard a nondeterministic automaton as a deterministic one whose states are lists of states.&lt;br /&gt;&lt;br /&gt;Our transition function is a -&gt; b -&gt; [a]. To use foldl, we need [a] -&gt; b -&gt; [a].&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;convert :: (a -&gt; b -&gt; [a]) -&gt; [a] -&gt; b -&gt; [a]&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;convert f m a = concatMap (\x -&gt; f x a) m&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;nondeterministic f s = foldl (convert f) [s]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Does the convert function remind you of something? We can easily change the code to work with Maybe - the automaton will be deterministic, but it will be able to abort the computation anytime. It could also ask the user about the next state using IO. It's the list monad.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;convert' :: (Monad m) =&gt; (a -&gt; b -&gt; m a) -&gt; m a -&gt; b -&gt; m a&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;convert' f m a = m &gt;&gt;= (\x -&gt; f x a)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;nondeterministic' :: (Monad m) =&gt; (a -&gt; b -&gt; m a) -&gt; a -&gt; [b] -&gt; m a&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;nondeterministic' f s = foldl (convert' f) (return s)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This function is called &lt;span style="font-family:courier new;"&gt;foldM&lt;/span&gt; and is available in Control.Monad.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;foldM :: (Monad m) =&gt; (a -&gt; b -&gt; m a) -&gt; a -&gt; [b] -&gt; m a&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Unfolding&lt;/span&gt;&lt;br /&gt;Suppose you have types a,b such that b = 1 + a b. Then, by substituting this equality into itself, we get&lt;br /&gt;&lt;br /&gt;b = 1 + ab = 1 + a(1 + ab) = 1 + a + aab = 1 + a + aa(1 + ab) = 1 + a + aa + aaa + aaab = ... = 1 + a + aa + aaa + ...&lt;br /&gt;&lt;br /&gt;b has changed into 1 + a + a a + a a a + ... This is the same as a list, [a].&lt;br /&gt;&lt;br /&gt;Equality of types x=y means that we can pair corresponding x's and y's. But we don't need that. Instead, we just need a map b -&gt; 1 + a b that doesn't have to be an isomorphism. We can change all "equals" signs in above reasoning to -&gt;:&lt;br /&gt;&lt;br /&gt;b -&gt; 1 + ab -&gt; 1 + a(1 + ab) -&gt; ... -&gt; 1 + a + aa + ... -&gt; [a]&lt;br /&gt;&lt;br /&gt;and it stays OK. So, given a function (b -&gt; 1 + a b), we get b -&gt; [a]. This is known as unfolding. This name is very suggestive - we &lt;span style="font-style: italic;"&gt;unfolded&lt;/span&gt; b into a list of a's. Since 1 + a is called in Haskell Maybe a, we have a higher order function&lt;br /&gt;&lt;br /&gt;unfold :: (b -&gt; Maybe (a, b)) -&gt; (b -&gt; [a])&lt;br /&gt;&lt;br /&gt;Exercise: Write it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Solution:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;pre&gt;&lt;br /&gt;unfold f x = case f x of&lt;br /&gt;            Nothing -&gt; []&lt;br /&gt;            Just (a,x') -&gt; a:(unfold f x')&lt;br /&gt;&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Data.List calls this function unfoldr.&lt;br /&gt;&lt;br /&gt;If you invert this reasoning, given a function (f :: 1 + a b -&gt; b) you get [a] -&gt; b. This is folding. &lt;span style="font-family:courier new;"&gt;f Nothing&lt;/span&gt; is our initial value, and&lt;span style="font-family:courier new;"&gt; f $ Just (a,b)&lt;/span&gt; tells how to combine a and b.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Fold vs unfold&lt;/span&gt;&lt;br /&gt;Some simple exercises. Recursion is not allowed directly, use only foldl, foldr and unfold.&lt;br /&gt;&lt;br /&gt;1. Write factorial.&lt;br /&gt;&lt;br /&gt;2. Write functions&lt;br /&gt;&lt;br /&gt;toBinary :: Integer -&gt; [Bool]&lt;br /&gt;fromBinary :: [Bool] -&gt; Integer&lt;br /&gt;&lt;br /&gt;that convert between a natural number and its binary representation.&lt;br /&gt;For example, fromBinary [False, True, True] == 6.&lt;br /&gt;&lt;br /&gt;3. Now you have binary numbers. Write &lt;a href="http://en.wikipedia.org/wiki/Exponentiation_by_squaring"&gt;exponentiation by squaring&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;power :: (Monoid a) =&gt; a -&gt; Integer -&gt; a&lt;br /&gt;&lt;br /&gt;Exponent will be nonnegative.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;A natural number is a list&lt;/span&gt;&lt;br /&gt;An important degenerate case of lists are natural numbers. A list of () is really a natural number (its length). This is &lt;a href="http://en.wikipedia.org/wiki/Unary_numeral_system"&gt;unary numeral system&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;foldl :: (a -&gt; b -&gt; a) -&gt; a -&gt; [b] -&gt; a&lt;br /&gt;&lt;br /&gt;If we take b = (), we get&lt;br /&gt;&lt;br /&gt;foldl' :: (a -&gt; a) -&gt; a -&gt; Integer -&gt; a&lt;br /&gt;&lt;br /&gt;This is n-th power of a function.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Other resources&lt;/span&gt;&lt;br /&gt;If you're interested in fold, check out these resources. &lt;span style="font-weight: bold;"&gt;They are really worth reading and will give you much insight and many intereresting ideas.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;* &lt;a href="http://www.cs.nott.ac.uk/~gmh/fold.ps"&gt;A tutorial on the universality and expressiveness of fold&lt;/a&gt;&lt;br /&gt;* &lt;a href="http://www.haskell.org/sitewiki/images/1/14/TMR-Issue6.pdf"&gt;The Monad.Reader 6&lt;/a&gt;&lt;br /&gt;* &lt;a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125"&gt;Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire&lt;/a&gt;&lt;br /&gt;* &lt;a href="http://www.cs.nott.ac.uk/~gmh/methods.pdf"&gt;Proof methods for structured corecursive programs&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Solution to the warmup exercise:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;map f = foldr (\a x -&gt; f x : a) []&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;compose = foldr (.) id&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;foldr f a xs = compose (map f xs) a&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here's another version of compose, by roconnor:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;compose l x = foldr ($) x l&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3679812208800765969-5062036139335198993?l=monoidal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://monoidal.blogspot.com/feeds/5062036139335198993/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3679812208800765969&amp;postID=5062036139335198993' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3679812208800765969/posts/default/5062036139335198993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3679812208800765969/posts/default/5062036139335198993'/><link rel='alternate' type='text/html' href='http://monoidal.blogspot.com/2009/08/some-thoughts-and-exercises-on-folding.html' title='Some thoughts and exercises on folding'/><author><name>g</name><uri>http://www.blogger.com/profile/04686862403622560424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry></feed>
