从Haskell中的文件解析二叉树

时间:2017-02-01 21:36:47

标签: haskell

我有编写Quiz Animal游戏的任务。我必须从文件中读取树数据(文件的结构是免费的)。游戏结束后可以在树中添加新数据(实际上(动物)将被替换为(Node(Animal)(Animal))。

我的问题是我无法解析AnimalsTree中的“database.txt”内容

示例“database.txt”(此内容是在调用“新游戏”之前通过写入生成的):

  

问题“飞吗?” (动物“鸟”)(问题“游泳吗?”(动物“鱼”)(动物“狗”))

修改 这是完整的代码:

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

但我得到以下错误:

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

1 个答案:

答案 0 :(得分:2)

这看起来是一个很好的开始!我只需要将readFile添加到您的main函数中以使其编译:

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

您可能需要从readFile切换到显式打开文件以进行读取,读取和关闭文件。这是因为readFile无法保证何时关闭文件,如果为writeFile提供了已经打开的文件的路径,则允许openFile失败。

您可以阅读hGetLinehClosehGetContents的文档,了解有关如何执行此操作的详细信息(但请注意readFile,因为它有相同的注意事项{{1}}确实如此。