<?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/'><id>tag:blogger.com,1999:blog-32850121.post6575095183792190513..comments</id><updated>2007-04-08T14:36:49.683-07:00</updated><title type='text'>Comments on Programming Experiments: Haskell Golf Scores</title><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://progexpr.blogspot.com/feeds/6575095183792190513/comments/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/6575095183792190513/comments/default'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/2006/11/haskell-golf-scores.html'/><author><name>a</name><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>3</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-32850121.post-6549929356866648565</id><published>2007-04-08T14:36:00.000-07:00</published><updated>2007-04-08T14:36:00.000-07:00</updated><title type='text'>I hope you're not tired of receiving other people'...</title><content type='html'>I hope you're not tired of receiving other people's implementations on here... I am learning myself and thought a reimplementation of your program here would be fun. And it was! So I hope my version elucidates some things, with a little commentary.&lt;BR/&gt;&lt;BR/&gt;It took a long time for me to get comfortable enough with monads that I could do IO the way I do in this program. I laud your implementation and I hope you'll keep on keepin' on. Haskell is hard to learn and the  type system often doesn't help. I started including annotations because everyone else does and it actually seems to help find bugs and improve the design.&lt;BR/&gt;&lt;BR/&gt;&gt; module GolfScore where&lt;BR/&gt;&gt; import Data.List    -- for the sort function&lt;BR/&gt;&lt;BR/&gt;One thing a friend told me is that you are going to want functions that take a simple type and return stuff inside a monad, rather than monkeying around with monad -&gt; monad typed functions. Actually in general do it as purely as possible; if you have to return in a monad that's fine but if you can return a pure value instead, do that; there are ways of lifting that function into the monad when you have to. Because the monad operations are all intended to help you glue functions with that kind of type together. Which is what I've got in this code:&lt;BR/&gt;&lt;BR/&gt;&gt; getName :: IO String&lt;BR/&gt;&gt; getName = putStr "Enter name: " &gt;&gt; getLine&lt;BR/&gt;&gt; &lt;BR/&gt;&gt; getScore :: IO Integer&lt;BR/&gt;&gt; getScore = putStr "Enter score: " &gt;&gt; getLine &gt;&gt;= return . read&lt;BR/&gt;&lt;BR/&gt;Then I combined these primitives to make one which handles getting a person's name and score. I decided it would be more convenient to carry them around in a 2-tuple rather than two lists, because it makes the relationship concrete.&lt;BR/&gt;&lt;BR/&gt;&gt; getNameAndScore :: Int -&gt; IO (String, Integer)&lt;BR/&gt;&gt; getNameAndScore holes = do&lt;BR/&gt;&gt;     name &lt;- getName&lt;BR/&gt;&gt;     scores &lt;- sequence $ replicate holes getScore&lt;BR/&gt;&gt;     return (name, sum scores)&lt;BR/&gt;&lt;BR/&gt;Sequence and replicate form the basis of my iteration in this program. It lets me avoid any explicit looping, because we're really just doing the same things over again and collecting the result. I recommend spending time reading the prelude, it helped me quite a bit to see what's there and built-in already. Anyhow, sequence and sequence_ are handy because they let you take a list of monadic actions and convert them into a list of results. mapM is similar, essentially applying a monad action to a list and collecting the result.&lt;BR/&gt;&lt;BR/&gt;Here are my output functions:&lt;BR/&gt;&lt;BR/&gt;&gt; showResult :: String -&gt; Integer -&gt; IO ()&lt;BR/&gt;&gt; showResult name score = putStrLn $ name ++ " got a score of " ++ (show score)&lt;BR/&gt;&gt; &lt;BR/&gt;&gt; showResults :: [(String, Integer)] -&gt; IO ()&lt;BR/&gt;&gt; showResults = mapM_ (uncurry showResult)&lt;BR/&gt;&lt;BR/&gt;So showResults is clearly intended to take the output of getNameAndScore. showResult probably could have been coded to take a 2-tuple but I like using uncurry and I don't like writing functions that take tuples unless I really have to. Pet peeve I guess. And there's the aforementioned mapM. The underscore variants tend to throw away their results, which is fine here, because showResult produces IO (), and mapM would give me back a list of [IO (), IO ()...]. Not something I care to keep around.&lt;BR/&gt;&lt;BR/&gt;And here is your essential function. I did add one thing, it sorts by score, showing the winner at the top. :)&lt;BR/&gt;&lt;BR/&gt;&gt; run :: Int -&gt; Int -&gt; IO ()&lt;BR/&gt;&gt; run count holes = do&lt;BR/&gt;&gt;     namesAndScores &lt;- sequence $ replicate count (getNameAndScore holes)&lt;BR/&gt;&gt;     let sorted = sortBy (\l r -&gt; compare (snd l) (snd r)) namesAndScores&lt;BR/&gt;&gt;     showResults sorted&lt;BR/&gt;&lt;BR/&gt;The sequence $ replicate construct there is the same as the one above, creating a list of monad actions and then evaluating them. I had a tendency when I was starting to try and write the second line as "sorted &lt;- sortBy ..." but that of course doesn't work because it is a pure function result. The let solves this problem. sortBy takes a function and a list; my function just pushes the compare into the second item of the tuple and sorts based on that, which happens to be the score. Then I show the results.</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/6575095183792190513/comments/default/6549929356866648565'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/6575095183792190513/comments/default/6549929356866648565'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/2006/11/haskell-golf-scores.html?showComment=1176068160000#c6549929356866648565' title=''/><author><name>fusiongyro</name><uri>http://www.blogger.com/profile/13365348872817885287</uri><email>noreply@blogger.com</email></author><thr:in-reply-to xmlns:thr='http://purl.org/syndication/thread/1.0' href='http://progexpr.blogspot.com/2006/11/haskell-golf-scores.html' ref='tag:blogger.com,1999:blog-32850121.post-6575095183792190513' source='http://www.blogger.com/feeds/32850121/posts/default/6575095183792190513' type='text/html'/></entry><entry><id>tag:blogger.com,1999:blog-32850121.post-8121715260487477195</id><published>2006-12-20T02:45:00.000-08:00</published><updated>2006-12-20T02:45:00.000-08:00</updated><title type='text'>The easiest step to improve your code is using lib...</title><content type='html'>The easiest step to improve your code is using library functions for recursion patterns.&lt;br /&gt;&lt;br /&gt;showResults = zipWithM showResult&lt;br /&gt;  where showResult x y = putStrLn (x ++ " got a score of " ++ show y)&lt;br /&gt;&lt;br /&gt;getScores count = &lt;br /&gt;  replicateM count (putStr "Enter score:" &gt;&gt; getLine)&lt;br /&gt;&lt;br /&gt;The scoring in run can be simplified a little bit.&lt;br /&gt;&lt;br /&gt;foldr ((+) . read) 0 scores ==&lt;br /&gt;foldr (+) 0 (map read scores) ==&lt;br /&gt;sum (map read scores)&lt;br /&gt;&lt;br /&gt;run can be done with replicateM, if it accumulates results as a list of pairs rather than a pair of lists.&lt;br /&gt;&lt;br /&gt;run count holes = do&lt;br /&gt;  results &lt;- replicateM count (do&lt;br /&gt;    putStr "Enter name:"&lt;br /&gt;    name &lt;-getLine&lt;br /&gt;    scores &lt;- getScores holes&lt;br /&gt;    return (name, scores))&lt;br /&gt;  showResults (unzip results)&lt;br /&gt;&lt;br /&gt;For good code, I would split this (trivially) into a game reading and a game printing function.&lt;br /&gt;&lt;br /&gt;For maximum brevity, inline the helpers and create the output IO actions while reading in the game.&lt;br /&gt;&lt;br /&gt;run count holes =&lt;br /&gt;  sequence_ =&lt;&lt; replicateM count (do&lt;br /&gt;    name &lt;- putStr "Enter name:" &gt;&gt; getLine&lt;br /&gt;    scores &lt;- replicateM holes (putStr "Enter Score:" &gt;&gt; getLine)&lt;br /&gt;    return $ putStrLn $ name ++ " got a score of "++show (sum (map read scores)))</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/6575095183792190513/comments/default/8121715260487477195'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/6575095183792190513/comments/default/8121715260487477195'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/2006/11/haskell-golf-scores.html?showComment=1166611500000#c8121715260487477195' title=''/><author><name>Brandon</name><email>noreply@blogger.com</email></author><thr:in-reply-to xmlns:thr='http://purl.org/syndication/thread/1.0' href='http://progexpr.blogspot.com/2006/11/haskell-golf-scores.html' ref='tag:blogger.com,1999:blog-32850121.post-6575095183792190513' source='http://www.blogger.com/feeds/32850121/posts/default/6575095183792190513' type='text/html'/></entry><entry><id>tag:blogger.com,1999:blog-32850121.post-1005345092817733260</id><published>2006-12-19T19:01:00.000-08:00</published><updated>2006-12-19T19:01:00.000-08:00</updated><title type='text'>The 'read' function is useful for translating a St...</title><content type='html'>The 'read' function is useful for translating a String to an Integer (or any other data type in the Read class).&lt;br /&gt;&lt;br /&gt;&gt; read "36" :: Integer&lt;br /&gt;36&lt;br /&gt;&lt;br /&gt;&gt; 7 + (read "19")&lt;br /&gt;26&lt;br /&gt;&lt;br /&gt;&gt; read "[1,2,3]" :: [Integer]&lt;br /&gt;[1,2,3]</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/6575095183792190513/comments/default/1005345092817733260'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/6575095183792190513/comments/default/1005345092817733260'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/2006/11/haskell-golf-scores.html?showComment=1166583660000#c1005345092817733260' title=''/><author><name>Bryan</name><uri>http://www.blogger.com/profile/00853885260874683916</uri><email>noreply@blogger.com</email></author><thr:in-reply-to xmlns:thr='http://purl.org/syndication/thread/1.0' href='http://progexpr.blogspot.com/2006/11/haskell-golf-scores.html' ref='tag:blogger.com,1999:blog-32850121.post-6575095183792190513' source='http://www.blogger.com/feeds/32850121/posts/default/6575095183792190513' type='text/html'/></entry></feed>