【问题标题】:How to read line by line from a file in Haskell如何从Haskell中的文件中逐行读取
【发布时间】:2016-04-25 21:00:05
【问题描述】:

我正在尝试制作一个程序,它应该从文件中逐行读取并检查它是否是回文,如果是,则打印。

我真的是haskell的新手,所以我唯一能做的就是打印出每一行,使用以下代码:

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

isPalindrom w = w==reverse w

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

【问题讨论】:

    标签: haskell


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      这是一种建议的方法

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

      括号中的部分是纯代码,类型为String-&gt;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 on)。在我们的例子中,第一项和第三项实际上是古文,第二项不是。我们的表达式计算如下

      unlines ["abcba", "K"]
      

      最后,unlineslines 的反面......它将再次连接项目,在其间插入换行符。

      "abcba\nK"
      

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

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

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

      然而,这种方法混合了纯代码和不纯代码,并且被认为比前者更不习惯 Haskell 代码。不过,您仍然会经常看到这种类型的东西!

      【讨论】:

      • 您好,感谢您的帮助,您能否详细解释一下“$”运算符和函数过滤器的工作原理?据我了解,过滤器检查文件内容的每一行中是否有“isPalindrome”,如果为真,则打印,对吗?那么为什么我需要在这里 unlines 呢?非常感谢!
      • 我添加了更多细节。
      • 还有一个问题,现在如果我每次找到回文时都想说“...是回文”,我应该在哪里添加“..是回文”部分?我不能说我有多感激:)
      • 在纯方法中,您可以使用map 添加到管道中的每个单独的字符串,例如unlines $ map (++ " is a palindrome") $ filter isPalindrome $ lines fileContent。使用 monadic 方法,您只需添加到 putStrLn,例如 putStrLn $ item ++ " is a palendrome"。在这种情况下,monadic 方法可能更容易理解,尽管我仍然喜欢保持纯粹。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-21
      • 2011-12-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多