2013-01-13 48 views
1

這是我再次:)。我嘗試編寫一個程序,將一個可以被5整除的行拷貝到另一個文件中。這裏是代碼(對不起,波蘭名):可被5整除的複製行

import IO 

przepiszConHelper :: Handle -> Handle -> Integer -> Integer -> IO() 
przepiszConHelper wejscie wyjscie liczba licznik = do 
    eof <- hIsEOF wejscie 
    if eof then return() 
     else 
      linia <- hGetLine wejscie 
      if (mod licznik liczba) == 0 then 
       hPutStrLn wyjscie linia 
      przepiszConHelper wejscie wyjscie liczba (licznik + 1) 

przepiszCon :: String -> String -> Integer -> IO() 
przepiszCon wejscie wyjscie liczba = do 
    wej <- openFile wejscie ReadMode 
    wyj <- openFile wyjscie WriteMode 
    przepiszConHelper wej wyj liczba 0 
    hClose wej 
    hClose wyj 

main = przepiszCoN "wejscie.txt" "wyjscie.txt" 5 

我認爲它應該工作...但我得到一個奇怪的錯誤:

przepisz.hs:6:9: 
    Parse error in pattern: if eof then return() else linia 

這是沒有意義的我。我在其他程序中一直使用相同的表達方式,並且它的工作方式非常糟糕。我試圖刪除這些行,並用不同的縮進來編寫它們(我記得之前我有一些空白問題)。但我仍然得到同樣的錯誤:(


--edit

OK,我第一個錯誤......它只是else do而不是else但這裏談到另一個問題:

przepisz.hs:11:25: parse error on input `przepiszConHelper' 

回答

3

的問題是在這裏:

if eof then return() 
    else 
     linia <- hGetLine wejscie 

事實上,這個問題是不是空白 - 你的問題是,你似乎期望do塊在子表達式內部擴展,事實並非如此。該else條款需要定義自己的do塊:

if eof then return() 
    else do 
     linia <- hGetLine wejscie 

還有另一個錯誤之後,但是:

if (mod licznik liczba) == 0 then 
    hPutStrLn wyjscie linia 
przepiszConHelper wejscie wyjscie liczba (licznik + 1) 

您缺少此ifelse條款。 if始終是Haskell中的一個表達式,因此它必須始終評估爲,其值爲。如果你想表達「做這個IO行動,如果條件爲真,否則什麼都不做」,你可以使用return()

if (mod licznik liczba) == 0 
    then hPutStrLn wyjscie linia 
    else return() 

標準庫甚至還包括功能when來表達這種想法:

when (mod licznik liczba == 0) $ hPutStrLn wyjscie linia 

如果你願意,你可以重寫外if表達了同樣的方式,並獲得這樣的:

przepiszConHelper :: Handle -> Handle -> Integer -> Integer -> IO() 
przepiszConHelper wejscie wyjscie liczba licznik = do 
    eof <- hIsEOF wejscie 
    when (not eof) $ do 
     linia <- hGetLine wejscie 
     when (mod licznik liczba == 0) $ hPutStrLn wyjscie linia 
     przepiszConHelper wejscie wyjscie liczba (licznik + 1) 
+1

FWIW,標準庫中'when'的位置在'Control.Monad'模塊中:'import Control.Monad(when)' – luqui

+0

@luqui:哦,麻煩了。這不是在前奏中?我的'.ghci'文件再次讓我誤入歧途。 –

3

我想提出一種不同的做事方式,主要是將純代碼與IO分離並使用更多標準功能。另外,我經常嘗試編寫比您所做的更小的功能,保持每個功能的簡單和易於維護。

首先讓我們保持列表的第n個元素。我們將通過將其與數字[1..]一起壓縮,然後僅保留數字可被n整除的數字。

przechowac :: Int -> [a] -> [a] 
przechowac n listy = [a| (a,i) <- zip listy [1..], i `mod` n == 0] 

因此,例如,

*Main> przechowac 3 [1..10] 
[3,6,9] 

接下來,讓我們留純,同時使用一個字符串的行:

przechowacLinie :: Int -> String -> String 
przechowacLinie n = unlines . przechowac n . lines 

*Main> putStrLn "Hej,\nHaskell\njest\nfantastyczny" 
Hej, 
Haskell 
jest 
fantastyczny 
*Main> putStrLn (przechowacLinie 2 "Hej,\nHaskell\njest\nfantastyczny") 
Haskell 
fantastyczny 

現在,讓我們把它包在一些IO中。我們會讓適用的功能,文件的功能,將其保存到一個輸出文件:(FilePathString一種代名詞,使輸入更清晰的簽名)

zastosowacFunkcje :: (String -> String) -> FilePath -> FilePath -> IO() 
zastosowacFunkcje f wejscie wyjscie = do 
    wej <- readFile wejscie 
    writeFile wyjscie (f wej) 

我可以使用是寫你的函數:

przepiszCon :: Int -> FilePath -> FilePath -> IO() 
przepiszCon liczba = zastosowacFunkcje (przechowacLinie liczba) 

事實上,這些天我一直使用像zastosowacFunkcje功能停止,現在我傾向於只是做

przepiszCon :: Int -> FilePath -> FilePath -> IO() 
przepiszCon n wejscie wyjscie = fmap (przechowacLinie n) (readFile wejscie) 
                >>= writeFile wyjscie 

因爲我覺得fmap太方便了。

相關問題