再次是我:)。我尝试编写一个程序,将可以被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
这对我来说毫无意义。我一直在其他程序中使用相同的表达式,它就像一个伤害。我试图删除这些行并用不同的缩进写出它们(我记得我以前遇到过一些白色空格问题)。但我仍然得到同样的错误:(。
- 修改
好的,我有第一个错误......它只是else do
而不是else
。但是这里出现了另一个问题:
przepisz.hs:11:25: parse error on input `przepiszConHelper'
答案 0 :(得分: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)
您错过了此else
的{{1}}条款。 if
始终是Haskell中的表达式,因此它必须始终评估为某些内容。如果您想表达“如果条件为真,请执行此if
操作,否则不执行任何操作”,您可以使用IO
:
return ()
标准库甚至包含表达这个想法的函数if (mod licznik liczba) == 0
then hPutStrLn wyjscie linia
else return ()
:
when
如果你愿意,你可以用同样的方式重写外部when (mod licznik liczba == 0) $ hPutStrLn wyjscie linia
表达式,并得到这样的结果:
if
答案 1 :(得分: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中。我们将创建一个将函数应用于文件的函数,将其保存到输出文件中:
zastosowacFunkcje :: (String -> String) -> FilePath -> FilePath -> IO ()
zastosowacFunkcje f wejscie wyjscie = do
wej <- readFile wejscie
writeFile wyjscie (f wej)
(FilePath
是String
的类型同义词,可以使类型签名更清晰。)
我可以用它来编写你的函数:
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
非常方便。