1

私は試験セッションの前にHaskellを学ぼうとしていますが、それでも私にとっては魔法です。今日、私はファイルを読み取り、その行を逆の順序で別のファイルに書き込むプログラムを作成しようとしました。結果?多くのエラー。これが私のコードです:

import IO

readLines :: Handle -> [String] -> [String]
readLines handler list = do
    eof <- hIsEOF handler
    if eof then list
        else do
            line <- hGetLine handler
            readLines handler (list ++ [line])

writeLines :: Handle -> [String] -> [String]
writeLines handler list = if length list == 0 then list
    else do
        line <- head list
        hPutStrLn handler line
        writeLines tail list

fileToList :: FilePath -> [String]
fileToList filename = do
    handler <- openFile filename ReadMode
    list <- (readLines handler [])
    hClose handler
    list

invLines :: FilePath -> FilePath -> IO ()
invLines input output = do
    handler <- openFile output WriteMode
    inverted <- reverse (fileToList input)
    writeLines handler inverted
    hClose handler

main = invLines "in.txt" "out.txt"

私の過ちを説明していただければ幸いです。

4

1 に答える 1

6

まず最初に、

IO ==> System.IO

次に、readLinesを見てみましょう(PS readFileはここでうまく機能します)

readLines :: Handle -> [String] -> [String] --You have to return an IO [String] here.
    readLines handler list = do
    eof <- hIsEOF handler
    if eof then return list --Return an IO list
        else do
            line <- hGetLine handler
            readLines handler (list ++ [line])

次へwriteLines(PSwriteFileも役立ちます)

writeLines :: Handle -> [String] -> [String] -- You have to return IO of something, I'd recommend ().
writeLines handler list = if length list == 0
    then list --Change to return ()
    else do
        line <- head list --Should be let here. Like let line = head list
        hPutStrLn handler line
        writeLines tail list -- Should be writeLines handler $ tail list instead.

次はfileToList

fileToList :: FilePath -> [String] --Has to be IO [String]
fileToList filename = do
    handler <- openFile filename ReadMode
    list <- (readLines handler [])
    hClose handler
    list -- Have to use return list

ああ、あなたは行を2回反転しているように見えるので、実際には非常に大きなコピールーチンになり、そこで逆を削除して、正しい結果を得ることができます。

最後のコード

import System.IO

readLines :: Handle -> [String] -> IO [String]
readLines handler list = do
    eof <- hIsEOF handler
    if eof 
    then return list
    else do
      line <- hGetLine handler
      readLines handler (line:list)

writeLines :: Handle -> [String] -> IO ()
writeLines handler list = if length list == 0 then return ()
    else do
        let line = head list
        hPutStrLn handler line
        writeLines handler $ tail list

fileToList :: FilePath -> IO [String]
fileToList filename = do
    handler <- openFile filename ReadMode
    list <- (readLines handler [])
    hClose handler
    return list

invLines :: FilePath -> FilePath -> IO ()
invLines input output = do
    handler <- openFile output WriteMode
    inputLines <- fileToList input
    writeLines handler inputLines
    hClose handler

main = invLines "in.txt" "out.txt"

そして、より多くのライブラリを使用して書き直しました。

invLines input output = do
    inputLines <- readFile input
    writeFile output . unlines . reverse . lines $ inputLines

invLines2 input output = 
    readFile input >>= writeFile output . unlines . reverse . lines

学ぶべき大きな教訓IOブロック内から通常の機能を返すことはできません。doIOを返す必要があります

于 2013-01-12T05:28:15.130 に答える