我试图制作一个应该从文件中逐行读取的程序,并检查它是否为palindrom,如果是,则打印。
我对haskell真的很陌生,所以我唯一能做的就是用这段代码打印出每一行:
main :: IO()
main = do
filecontent <- readFile "palindrom.txt"
mapM_ putStrLn (lines filecontent)
isPalindrom w = w==reverse w
问题是,我不知道如何逐行去检查该行是否是一个回文(请注意,在我的文件中,每行只包含一个单词)。谢谢你的帮助。
答案 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"]
最后,unlines
与lines
相反....它会再次合并项目,在两者之间插入换行符。
"abcba\nK"
由于STDIO本身是String
,因此可以输出。
请注意,使用非纯函数输出String
列表是完全可以的,如下所示
forM ["1", "2", "3"] $ \item -> do
putStrLn item
然而,这种方法混合了纯粹的和不纯的代码,并且被认为比前者稍微不那么惯用的Haskell代码。尽管如此,你仍然会看到这种类型的东西!