{"id":1002011,"date":"2009-01-18T12:10:40","date_gmt":"2009-01-18T17:10:40","guid":{"rendered":"http:\/\/www.elharo.com\/blog\/?p=1002011"},"modified":"2009-01-18T12:10:40","modified_gmt":"2009-01-18T17:10:40","slug":"transpose","status":"publish","type":"post","link":"https:\/\/www.elharo.com\/blog\/software-development\/haskell\/2009\/01\/18\/transpose\/","title":{"rendered":"transpose"},"content":{"rendered":"<p><cite><a href=\"http:\/\/book.realworldhaskell.org\/read\/functional-programming.html\">Real World Haskell<\/a><\/cite>, Exercise 4, p. 84:<\/p>\n<p>Write a program that transposes the text in a file. For instance, it should convert &#8220;hello\\nworld\\n&#8221; to &#8220;hw\\neo\\nlr\\nll\\nod\\n&#8221;.<br \/>\n<!--more--><\/p>\n<pre><code>cc :: String -> String -> String\r\ncc x y = x ++ y ++ \"\\n\"\r\n\r\ntransposeSingle :: String -> String\r\ntransposeSingle [] = []\r\ntransposeSingle (x:xs) = x : '\\n' : (transposeSingle xs)\r\n\r\n-- the accumulator string and the next line\r\ntransposeDouble :: String -> String -> String\r\ntransposeDouble x y = concat (zipWith (cc) (lines x) (lines (transposeSingle y)))\r\n\r\ntransposeEven :: [String] -> String\r\ntransposeEven [] = []\r\ntransposeEven [x] = (transposeSingle x) \r\ntransposeEven (x:xs) = foldl (transposeDouble) (transposeSingle x) xs\r\n\r\ntranspose :: String -> String\r\ntranspose s = transposeEven (pad (maxLength s) (lines s))\r\n\r\n-- pad each line with spaces to maximum length\r\nmaxLength :: String -> Int\r\nmaxLength s = maximum (map length (lines s))\r\n\r\npad :: Int -> [String] -> [String]\r\npad _ [] = []\r\npad n (x:xs) = (padOneLine (n - (length x)) x) : (pad n xs)\r\n\r\npadOneLine :: Int -> String -> String\r\npadOneLine n s = if n > 0\r\n                 then padOneLine (n-1) (s ++ \".\")\r\n                 else s<\/code><\/pre>\n<p>The exercise wasn&#8217;t clear on what you should do when not all lines were the same size, so I padded them out with periods.<\/p>\n<p>This took way longer to implement than it should have, and I had to use several functions from later parts of the book. I certainly could have implemented this faster in Java or, to pick a language I haven&#8217;t been using day in and day out for 14 years, Python. Doubtless an experienced Haskell programmer could come up with a simpler implementation.<\/p>\n<p>On the positive side, the interactive ghci shell was a big help in debugging this, and by their very nature Haskell&#8217;s pure functions are very amenable to testing and debugging in isolation. However, I still have to learn how to do real test driven development in Haskell. (One thing I proved to myself a couple of jobs ago  was that TDD matters a lot more than what language you code in. I figured this out after I realized I could write correct Python code faster than the professional Python programmers we had hired because I was using TDD and they weren&#8217;t. This despite the fact that I  knew next to no Python and they had years of experience in the language. Of course, an experienced Python programmer who did use test-driven development could still wipe the floor with me. )<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Real World Haskell, Exercise 4, p. 84: Write a program that transposes the text in a file. For instance, it should convert &#8220;hello\\nworld\\n&#8221; to &#8220;hw\\neo\\nlr\\nll\\nod\\n&#8221;.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[74],"tags":[],"class_list":["post-1002011","post","type-post","status-publish","format-standard","hentry","category-haskell"],"_links":{"self":[{"href":"https:\/\/www.elharo.com\/blog\/wp-json\/wp\/v2\/posts\/1002011","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.elharo.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.elharo.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.elharo.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.elharo.com\/blog\/wp-json\/wp\/v2\/comments?post=1002011"}],"version-history":[{"count":2,"href":"https:\/\/www.elharo.com\/blog\/wp-json\/wp\/v2\/posts\/1002011\/revisions"}],"predecessor-version":[{"id":1002013,"href":"https:\/\/www.elharo.com\/blog\/wp-json\/wp\/v2\/posts\/1002011\/revisions\/1002013"}],"wp:attachment":[{"href":"https:\/\/www.elharo.com\/blog\/wp-json\/wp\/v2\/media?parent=1002011"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.elharo.com\/blog\/wp-json\/wp\/v2\/categories?post=1002011"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.elharo.com\/blog\/wp-json\/wp\/v2\/tags?post=1002011"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}