1

I have task to write Quiz Animal game. I have to read Tree data from file (the structure of file is free). After end of game is possible to be added new data in tree(actually (Animal) to be replace by (Node (Animal) (Animal)).

My problem is that i can't parse content of "database.txt" in AnimalsTree

Example "database.txt" (this content is generated with writing before call 'New Game'):

Question "Is it fly?" (Animal "Bird") (Question "Is it swim?" (Animal "Fish") (Animal "Dog"))

EDIT This is full code:

module Main where
import System.IO
data AnimalsTree = Animal String | Question String AnimalsTree AnimalsTree deriving (Read, Show)
-- Видовете отговори на потребителя
data Answer = Yes | No

main :: IO ()
main = do root <- "database.txt"
          play (read root)
          return ()

play :: AnimalsTree -> IO AnimalsTree
play root = do putStrLn "Think of an animal, I will try to guess what it is..."
               newRoot <- play' root
               writeFile "database.txt" (show newRoot)
               playAgain <- ask "Do you want to play again?"
               case playAgain of
                   Yes -> play newRoot
                   No  -> do putStrLn "Bye!"
                             return newRoot

play' :: AnimalsTree -> IO AnimalsTree
play' question@(Question q l r) = do ans <- ask q
                                     case ans of
                                        Yes -> do y <- play' l
                                                  return $ Question q y r
                                        No  -> do n <- play' r
                                                  return $ Question q l n

play' animal@(Animal _) = do ans <- ask $ "Are you thinking of " ++ show' animal ++ "?"
                             case ans of
                                Yes -> do putStrLn "I win! :)"
                                          return animal
                                No  -> do putStrLn "I give up, you win!"
                                          getNewAnimal animal


getNewAnimal :: AnimalsTree -> IO AnimalsTree
getNewAnimal animal = do putStrLn "Please help me!"
                         putStrLn "What is name of yout animal?"
                         name <- getLine
                         let newAnimal = Animal name
                         putStrLn $ "Now please enter a question that answers yes for " ++ show' newAnimal ++ " and no for " ++ show' animal
                         question <- getLine
                         return $ Question question newAnimal animal

ask :: String -> IO Answer
ask s = do putStrLn $ s ++ " (Yes/No)"
           getAnswer

getAnswer :: IO Answer
getAnswer = do ans <- getLine
               putStrLn ""
               case ans of
                   "y" -> return Yes
                   "Y" -> return Yes
                   "yes" -> return Yes
                   "Yes" -> return Yes
                   "n" -> return No
                   "N" -> return No
                   "no" -> return No
                   "No" -> return No
                   _   -> putStrLn "This is incorect answer! Please try again with value in 'Yes' or 'No'!" >> getAnswer

show' (Animal name) = (if elem (head name) "AEIOUaeiou" then "an " else "a ") ++ name
show' (Question q _ _) = q

But I get following error:

test3.hs:10:19:
    No instance for (Read (IO AnimalsTree))
      arising from a use of ‘read’
    In a stmt of a 'do' block: root <- read "database.txt"
    In the expression:
      do { root <- read "database.txt";
           play (root);
           return () }
    In an equation for ‘main’:
        main
          = do { root <- read "database.txt";
                 play (root);
                 return () }
6
  • 5
    You've already derived Read. Doesn't that give you a parser for free? Or, more to the point: What did you try, what did you expect to happen, and what happened instead? Commented Feb 1, 2017 at 22:20
  • I edit my post! Commented Feb 1, 2017 at 23:27
  • You cannot return a pure value from the main function. Also, return is not the return from languages like C or Java, it's a function from a type class called Monad, a very powerful tool of abstraction. Commented Feb 1, 2017 at 23:34
  • Furthermore, looking at your code, you write animals :: [Tree] = fileString, which is syntactically incorrect, but you never use the value animals anywhere is your code. Commented Feb 1, 2017 at 23:38
  • Ok,thank you! animals :: [Tree] = fileString is incorect. How can i cast read content to Tree and print it in console? Commented Feb 2, 2017 at 0:08

1 Answer 1

2

This looks like a great start! I only needed to add readFile to your main function to get it to compile:

main = do root <- readFile "database.txt"

It is possible that you may need to switch from readFile to explicitly opening the file for reading, doing the reading, and closing the file. This is because readFile does not guarantee when it will close the file, and writeFile is allowed to fail if it is given a path to a file that's already open.

You can read the documentation for openFile, hGetLine, and hClose for further details on how to do this (but beware hGetContents, as it has the same caveats readFile does).

Sign up to request clarification or add additional context in comments.

1 Comment

You are hero! Thank you! Just save my life! ^.^

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.