user14595256
user14595256

Reputation:

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

I am working on a project which need to load a map into the game first from a txt file, eg "map.txt". The kodable is the main function. First, the game will ask the player to load a map. So, in that case, the player will input map.txt. Then, I am trying to use the function loadMap to recursively put the map into array of string and stored in map. Finally, I will use the function outputMap to output the map I have load. As I am still a beginner in Haskell, so I am having trouble in debugging this part.

Upvotes: 0

Views: 815

Answers (2)

DrSooch
DrSooch

Reputation: 322

I see that you have already decided on sticking with your first answer. But I just would like to throw this solution here, just so you have an idea for the future. I will be using some "complex" functions that are probably out of your reach as of now.

Firstly, kodable can be reduced to:

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

The funky >>= function is just a way to deal with the IO Monad so we don't have to unwrap and wrap values. I won't go into details because its out of the scope of this question.

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

All this function does is print out the prompt and then get whatever input is typed in. The >> simply ignores the returned value on the left.

readFile does what you expect, it takes the filename from getMapFile and reads the contents of a file.

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

-- OR 

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

The final function here does exactly what loadMap and outputMap do in your code. lines is equivalent to loadMap, it splits the input file into separate strings based on newline characters. I get that you are trying to think recursively and just learning, but there are many useful functions out there to make your life easier.

After the contents of the file are split into the lines, we can use the Monadic Map function mapM_, which essentially applies putStrLn to every line in the list.

Upvotes: 1

user14595256
user14595256

Reputation:

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

I have tried the readFile method. Not exactly the way I was going to do. But I think I will still stick to that first. Thank you!

Upvotes: 0

Related Questions