[Haskell-cafe] Haskell Pangolins
ddarius at hotpop.com
Thu Dec 30 00:05:58 EST 2004
I've rewritten it closer to the way I would have written it. Most of the changes
are minor syntactic changes that you may or may not agree with. Probably the most
confusing part of the original code was the declaration of the Node datatype as
a (sum of) record(s), then the subsequent ignoring of the fact that it is a record.
In my experience, most Haskell programmer's would not (for better or worse) use a
record in this case. The comments I've added are with regards to the original
source code; compare this version and yours to see the differences. As far as
how the code actually works, it seems to be the most natural implementation.
-- Pangolins in Haskell
-- A simple animal guessing game
module Main ( main ) where
import Control.Monad ( liftM )
-- declared as record, but not used as record
= Guess String
| Question String Node Node
-- putStrLn s == putStr s >> putStr "\n"
ask question = do
getLine -- m >>= return == m (one of the monad laws)
isYes "y" = True
isYes "yes" = True
isYes "Y" = True
isYes "YES" = True
isYes _ = False
| c `elem` "aeiou" = "an " ++ fullstring
| otherwise = "a" ++ fullstring
rewrite (Guess name) = do
reply <- ask ("Is it " ++ withArticle name ++ "?") -- superfluous parens
if isYes reply -- superfluous parens
putStr "Computer wins!\n"
return (Guess name)
newName <- ask "What is it, then?"
newQuestion <- newQuestion name newName
rewrite (Question text ifYes ifNo) = do
reply <- ask text
if isYes reply
then liftM (flip (Question text) ifNo) (rewrite ifYes)
else liftM (Question text ifYes) (rewrite ifNo)
newQuestion a1 a2 = do -- superfluous parens
text <- ask ("Tell me a question that can be used to distinguish between " ++ withArticle a1 ++ " and " ++ withArticle a2 ++ ".")
answer <- ask ("What would the answer to your question be if it was " ++ withArticle a1 ++ "?")
if isYes answer -- superfluous parens
then return (Question text (Guess a1) (Guess a2))
else return (Question text (Guess a2) (Guess a1))
-- superfluous parens
duck = Guess "duck"
dog = Guess "dog"
initialNode = Question "Does it quack?" duck dog
-- superfluous 'do'
main = play initialNode
play :: Node -> IO ()
play node = do
rewrittenNode <- rewrite node
playAgain <- ask "Play again?"
if not (isYes playAgain) then putStrLn "Goodbye for now." -- superfluous 'do'
else play rewrittenNode -- superfluous 'do'
More information about the Haskell-Cafe