簡體   English   中英

在Haskell與IO monad斗爭

[英]Struggling with IO monad in 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

我認為問題在於您的思考勢在必行。 在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. 既然您具有解析行的功能,則parseEntries變得很簡單。 使用lines函數將內容按行分割,然后 parseLine 映射到每一行。

  2. tuplesToStrings可以寫得更簡單,因為tuplesToStrings = map tupleToString

  3. 我看不到tuplesToString將如何幫助您。 它的類型不匹配的返回類型parseLineparseLine返回的列表(String, Int)tuplesToString預計的列表(Int, Char) )。 而且它甚至不會在單詞之間或行之間插入空格。 這是serializeEntries的可能實現(使用Text.Printf模塊):

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM