2017-02-01 3 views
1

У меня есть задача написать игру Quiz Animal. Мне нужно прочитать данные дерева из файла (структура файла бесплатна). После окончания игры можно добавить новые данные в дерево (на самом деле (Animal), которое должно быть заменено на (Node (Animal) (Animal)).Разбор двоичного дерева из файла в Haskell

Моя проблема в том, что я не могу разобрать содержимое базы данных. .txt»в AnimalsTree

Пример "database.txt"(это содержание генерируется с записью перед вызовом 'New Game'):

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

EDIT Это полный код:

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' [email protected](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' [email protected](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 

Но я получаю следующее сообщение об ошибке:

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() } 
+5

Вы уже получили 'Read'. Разве это не дает вам парсер бесплатно? Или, более того: что вы пытались, что вы ожидали, и что произошло вместо этого? –

+0

Я редактирую свой пост! –

+0

Вы не можете вернуть чистое значение из функции 'main'. Кроме того, 'return' не является« возвратом »на таких языках, как C или Java, это функция из класса типа« Monad », очень мощного инструмента абстракции. – ThreeFx

ответ

2

Это выглядит как отличный старт! Я только необходимо добавить readFile к вашей main функции, чтобы получить его для компиляции:

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

Вполне возможно, что вам может понадобиться, чтобы перейти от readFile явно открыть файл для чтения, делая чтение и закрытие файла , Это связано с тем, что readFile не гарантирует, когда он закроет файл, и writeFile разрешено сбой, если ему задан путь к файлу, который уже открыт.

Вы можете прочитать документацию по openFile, hGetLine и hClose для получения более подробной информации о том, как это сделать (но остерегайтесь hGetContents, так как она имеет те же предостережения readFile делает).

+0

Ты герой! Спасибо! Просто спаси мою жизнь! ^. ^ –

Смежные вопросы