如何从Haskell中的文件逐行读取

时间:2016-04-25 21:00:06

标签: haskell

我试图制作一个应该从文件中逐行读取的程序,并检查它是否为palindrom,如果是,则打印。

我对haskell真的很陌生,所以我唯一能做的就是用这段代码打印出每一行:

main ::  IO()
  main = do
  filecontent <- readFile "palindrom.txt"
  mapM_ putStrLn (lines filecontent)

isPalindrom w = w==reverse w

问题是,我不知道如何逐行去检查该行是否是一个回文(请注意,在我的文件中,每行只包含一个单词)。谢谢你的帮助。

2 个答案:

答案 0 :(得分:3)

查看filter功能。您可能不希望将所有处理放在一行上,而是使用 let 表达式。此外,您的缩进已关闭:

main :: IO ()
main = do
  filecontent <- readFile "palindrom.txt"
  let selected = filter ... filecontent
  ...

答案 1 :(得分:2)

这是一种建议的方法

main ::  IO()
main = do
  filecontent <- readFile "palindrom.txt"
  putStrLn (unlines $ filter isPalindrome $ lines filecontent)

isPalindrome w = w==reverse w

parens中的部分是纯代码,它的类型为String->String。通常最好尽可能地隔离纯代码,因为代码往往是最容易推理的,并且通常更容易重用。

您可以将数据视为该部分从右到左流动,由($)运算符分解。首先,将内容拆分为单独的行,然后仅过滤回文,最后将完整输出重建为字符串。另外,因为Haskell是懒惰的,即使看起来它将输入视为内存中的单个String,它实际上只是根据需要提取数据。

编辑添加额外信息....

好的,所以soln的核心是纯粹的部分:

unlines $ filter isPalindrome $ lines filecontent

($)的工作方式是通过评估右边的函数,然后使用它作为左边的东西的输入。在这种情况下,filecontent是文件的完整输入(String,包括换行符),输出为STDOUT(也是包含换行符的完整字符串)。

让我们通过这个过程跟踪样本输入,“abcba \ n1234 \ nK”

unlines $ filter isPalindrome $ lines "abcba\n1234\nK"

首先,行会将其分解为行数

unlines $ filter isPalindrome ["abcba", "1234", "K"]

请注意,行的输出正被输入到过滤器的输入中。

那么,过滤器做什么?注意它的类型

filter :: (a -> Bool) -> [a] -> [a]

这需要2个输入参数,第一个是函数(isPalendrome是),第二个是项目列表。它将使用函数测试列表中的每个项目,其输出是相同的列表输入,减去函数选择删除的项目(返回False开启)。在我们的例子中,第一和第三项实际上是苍白的,第二项不是。我们的表达式评估如下

unlines ["abcba", "K"]

最后,unlineslines相反....它会再次合并项目,在两者之间插入换行符。

"abcba\nK"

由于STDIO本身是String,因此可以输出。

请注意,使用非纯函数输出String列表是完全可以的,如下所示

forM ["1", "2", "3"] $ \item -> do
    putStrLn item

然而,这种方法混合了纯粹的和不纯的代码,并且被认为比前者稍微不那么惯用的Haskell代码。尽管如此,你仍然会看到这种类型的东西!