在Haskell中与IO monad一起苦苦挣扎

时间:2013-12-10 10:46:11

标签: io haskell

所以我有两个文件包含以下内容:

File 1:
    Tom 965432145  
    Bill 932121234

File 2:
      Steve 923432323  
      Tom 933232323

我想合并它们并将结果输出写入名为'out.txt'的文件。 我写了这个函数来处理重复项(当同一个名字出现不止一次时,它会选择最终文件中的数字)。

该函数调用选择:

choosing :: [String] −> Int −> Int −> Int
choosing ("Name_of_person":_) num1 _ = num1 
choosing _ num1 num2
        | num2 ‘div‘ 100000000 == 2 = num2
        | otherwise = num1

这是我对此的尝试:

import System.IO
import Data.Char

choosing :: [String] −> Int −> Int −> Int
choosing name num1 _ = num1
choosing _ num1 num2
  | num2 `div` 100000000 == 2 = num2
  | otherwise = num1

main :: IO ()
main = do 
   in1 <- openFile "in1.txt" ReadMode
   in2 <- openFile "in2.txt" ReadMode
   out <- openFile "out.txt" WriteMode
   processData in1 in2 out
   hClose in1
   hClose in2
   hClose out



processData :: Handle -> Handle -> Handle -> IO ()
processData in1 in2 out =
    do ineof <- hIsEOF in1
       ineof2 <- h2IsEOF in2
        if ineof && ineof2
            then return ()
            else do inpStr <- hGetLine in1
                    inp2Str <- h2GetLine in2
                    num1Int <- num1GetNumber in1
                    num2Int <- num2GetNumber in2
                    if inpStr = inp2Str 
                        then PutStrLn out (impStr choosing inpStr num1Int num2Int )
                        else PutStrLn out (inpStr num1Int)
                             PutStrLn out (inp2Str num2Int)
                             processData in1 in2 out

然而这对我来说是有道理的,它没有编译,经过一段时间试图调试这个我现在开始认为这里有一些严重的错误,所以我非常感谢你的帮助。

这是我先尝试更简单的事情:

import System.IO
import Data.Char


choosing name num1 _ = num1
choosing _ num1 num2
  | num2 `div` 100000000 == 2 = num2
  | otherwise = num1

main :: IO ()
main = do 
   in1 <- openFile "in1.rtf" ReadMode
   in2 <- openFile "in2.rtf" ReadMode
   out <- openFile "out.rtf" WriteMode
   mainloop in1 out
   mainloop in2 out
   hClose in1
   hClose in2
   hClose out


mainloop :: Handle -> Handle -> IO ()
mainloop _ out =
  do ineof <- hIsEOF in
     if ineof
       then return ()
       else do inpStr <- hGetLine in
               hPutStrLn out (inpStr)
               mainloop in out

但它也不起作用......

更新:

所以基本上我一直试图解决我的问题,我得到的所有提示,我设法做到了这一点:

import System.IO
import Data.Char

- Main function to run the program

main = do
  entries1 <- fmap parseEntries $ readFile "in1.txt"
  entries2 <- fmap parseEntries $ readFile "in2.txt"
  writeFile "out.txt" $ serializeEntries $ mergeEntries entries1 entries2

- Function to deal with duplicates

choosing name num1 _ = num1
choosing _ num1 num2
  | num2 `div` 100000000 == 2 = num2
  | otherwise = num1

- Function to read a line from a file into a tuple
Now i need help making this function 'cover' the whole file, and not just one line of it.

parseLine :: String -> (String, Int)
parseLine xs = (\(n:i:_) -> (n, read i)) (words xs)


- A function that receives entries, merges them into a single string so that it can be writen to a file.

import Data.Char

tupleToString :: (Int, Char) -> [Char]
tupleToString x = (intToDigit.fst) x:(snd x):[]

tuplesToStrings [] = []
tuplesToStrings (x:xs) = tupleToString x : tuplesToStrings xs

tuplesToString xs = (concat . tuplesToStrings) xs

2 个答案:

答案 0 :(得分:2)

我认为问题在于你的想法太迫切了。在Haskell中,您通常将解决方案拆分为小块,每个块只做一件事。对一个小块进行推理要容易得多,并且在其他部分重用该块也更容易。例如,以下是我将如何细分此问题的代码:

parseEntries :: String -> [(String, Int)]

接收文件内容并解析条目的函数。如果in1.txt的内容会返回[("Tom", 965432145), ("Bill", 932121234)]


mergeEntries :: [(String, Int)] -> [(String, Int)] -> [(String, Int)]

从两个文件接收条目并合并它们的函数。


serializeEntries :: [(String, Int)] -> String

接收条目的函数,将它们合并为单个字符串,以便可以将其写入文件。


定义了这些函数后,main变得如此简单:

main = do
  entries1 <- fmap parseEntries $ readFile "in1.txt"
  entries2 <- fmap parseEntries $ readFile "in2.txt"
  writeFile "out.txt" $ serializeEntries $ mergeEntries entries1 entries2

答案 1 :(得分:0)

回复您的更新代码:

  1. 现在你有一个解析一条线的功能,parseEntries很容易。使用lines功能按行拆分内容,然后 parseLine映射到每一行。

  2. tuplesToStrings可以写得更加简单tuplesToStrings = map tupleToString

  3. 我不知道tuplesToString将如何帮助您。其类型与parseLine返回的类型不匹配(parseLine返回(String, Int)列表,而tuplesToString需要(Int, Char)列表。它甚至不会在单词之间或行之间插入空格。 以下是serializeEntries的可能实现(使用Text.Printf模块):

    serializeEntries entries = concatMap (uncurry $ printf "%s %d\n") entries