【问题标题】:Haskell iterate throught list with functionHaskell用函数遍历列表
【发布时间】:2017-11-10 00:54:38
【问题描述】:

我刚刚编写的一些 Haskell 代码有问题。我只是一个初学者,所以我对 Haskell 的语法不太了解,现在这个错误刚刚弹出,我不知道如何摆脱它。

无法将预期类型“[Bool]”与实际类型“Bool”匹配

 grep :: String -> IO()
 grep x = do
   fileContent <- readFile "/home/User/Desktop/foo.txt"
   let fileRows = lines fileContent
   let rowNumbers = -1
   if (map (isInfixOf x) fileRows == True) 
   then do let rowNumbers2 = rowNumbers
           let rowNumbers = rowNumbers2+1
           putStrLn ("[" ++ show(rowNumbers) ++ "] : " ++ x)
   else do let rowNumbers2 = rowNumbers
           let rowNumbers = rowNumbers2+1
           print "False"

我想检查fileContent 是否包含单词x。如果是,我想打印行和行号,否则我想继续搜索直到到达文件末尾。如何遍历fileRows 以检查该单词是否在其中?

【问题讨论】:

    标签: haskell functional-programming


    【解决方案1】:

    这里有一个更简单的方法来完成你想要完成的事情:

    我们从像以前一样读取文件开始,但是 fmap 在它上面行,所以我们不需要使用另一个变量。然后我们使用zipWith 来运行 contains 函数。它需要我们正在搜索的字符串、一行和一个行号。

    行号来自 [1..] 部分。这是无限列表的语法糖,从 1 开始并永远增加 1,所以 [1,2,3..] 因为 zipWith 需要 2 个列表,所以它只需要从这个无限列表中获取所需的数量。

    它检查该行是否存在,如果存在,则创建字符串,如果不存在则返回 Nothing。然后我们调用catMaybes,它接受一个maybes 列表,并返回所有的just 值。

    现在我们有了包含 grepped 字符串的每一行的输出字符串,所以我们只需要映射列表并打印它。 mapM_ 与 map 类似,不同之处在于它采用单子操作,将其应用于列表中的每个项目,并丢弃结果。

    通过像这样拆分函数,我们还可以创建一个不错的纯函数,而不是在不需要时使用一个长的 IO 函数。

    import Data.List (isInfixOf)
    import Data.Maybe (catMaybes)
    
    grep x = do
        fileContent <- lines <$> readFile "foo.txt"
        let result = catMaybes $ zipWith (contains x) fileContent [1..]
        mapM_ putStrLn result
    
    contains x y lineNum
        | x `isInfixOf` y = Just $ "[" ++ show lineNum ++ "] : " ++ y
        | otherwise = Nothing
    

    给定一个文件 foo.txt:

    apple
    banana
    orange
    apple banana
    orange cherry
    cherry apple
    

    它输出:

    λ> grep "apple"
    [1] : apple
    [4] : apple banana
    [6] : cherry apple
    λ> grep "foo"
    λ> grep "orange"
    [3] : orange
    [5] : orange cherry
    λ> 
    

    【讨论】:

      【解决方案2】:

      在这一行中,您将一个函数映射到 fileRows,因此您将返回一个 Bool 数组。

      map (isInfixOf x) fileRows == True
      

      您要做的是测试是否有任何行包含 x。如果您使用 any 而不是 map,它应该可以工作。

      any (isInfixOf x) fileRows == True
      

      【讨论】:

      • 感谢错误消失了,但它不会一次循环遍历列表,然后进入 if 语句,而是一次全部进入,然后再进入它
      • 您的代码看起来不像惯用的 Haskell。我认为更好的方法是找到索引然后打印出来。 hackage.haskell.org/package/base-4.2.0.0/docs/… 使用 findIndex 获取 Maybe Int。如果什么都不是,则打印错误,否则打印您要打印的内容
      • a == Truea 相同。
      猜你喜欢
      • 2011-11-25
      • 1970-01-01
      • 2018-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-06
      • 2019-03-17
      • 1970-01-01
      相关资源
      最近更新 更多