Haskell IO:读取整个文本文件

Haskell IO: Reading the whole text file

import System.IO

import Text.Printf

kodable :: IO()
kodable = do
    printf "Please load a map : "
    file <- getLine
    mapFile <- openFile file ReadMode
    let map = loadMap [] mapFile
    hClose mapFile
    printf "Read map successfully! \n"
    printf "Initial:\n"
    outputMap map
    
loadMap :: [String] -> FilePath -> [String]
loadMap map fp = do
    finished <- hIsEOF fp
    new_map <- if not finished
               then map ++ [hGetLine fp]
               else return ()
    loadMap new_map fp
    
outputMap :: [String] -> IO()
outputMap (x) = printf "%s\n" x
outputMap (x:xs) = do
    printf "%s\n" x
    outputMap xs

我正在开发一个项目,需要先从 txt 文件中将地图加载到游戏中,例如“map.txt”。 kodable 是主要功能。 首先,游戏会要求玩家加载地图。所以,在那种情况下,玩家将输入map.txt。然后,我尝试使用函数 loadMap 递归地将地图放入字符串数组并存储在 map 中。最后,我将使用函数 outputMap 输出我加载的地图。 由于我还是Haskell的初学者,所以我在调试这部分时遇到了麻烦。

import System.IO

import Text.Printf

kodable :: IO()
kodable = do
    printf "Please load a map : "
    file <- getLine
    map <- readFile file
    printf "Read map successfully! \n"
    printf "Initial:\n"
    outputMap map

outputMap :: String -> IO()
outputMap (x) = printf "%s\n" x
outputMap (x:xs) = do
    printf "%s\n" x
    outputMap xs

我试过readFile方法。不完全是我打算做的方式。但我想我还是会先坚持那个。谢谢!

我看到你已经决定坚持你的第一个答案。但我只是想把这个解决方案放在这里,让你对未来有一个想法。我将使用一些“复杂”的功能,这些功能目前您可能还无法使用。

首先,kodable可以简化为:

kodable :: IO ()
kodable = getMapFile >>= readFile >>= outputMap

时髦的 >>= 函数只是一种处理 IO Monad 的方法,因此我们不必对值进行解包和包装。我不会详细介绍,因为它超出了这个问题的范围。

getMapFile :: IO String
getMapFile = putStr "Please load a map: " >> getLine

这个函数所做的就是打印出提示,然后获取输入的任何内容。>> 只是忽略左侧的返回值。

readFile 如您所愿,它从 getMapFile 获取文件名并读取文件内容。

outputMap :: String -> IO ()
outputMap = mapM_ putStrLn . lines

-- OR 

outputMap :: String -> IO ()
outputMap fileContents = mapM_ putStrLn $ lines fileContents

此处的最终函数与 loadMapoutputMap 在您的代码中所做的完全相同。 lines 等同于 loadMap,它根据换行符将输入文件拆分为单独的字符串。我知道您正在尝试递归思考并只是在学习,但是有许多有用的功能可以让您的生活更轻松。

将文件内容拆分成行后,我们可以使用 Monadic Map 函数 mapM_,它实际上将 putStrLn 应用于列表中的每一行。