【问题标题】:Make Haskell List Recursion function more efficient让 Haskell 列表递归函数更高效
【发布时间】:2016-05-06 06:46:10
【问题描述】:

我编写了一个函数,它将比较两个列表并检查第一个是否是第二个的前缀,并且必须使用递归来完成。

例如:

prefix [1,2] [1,2,3]
>True
prefix [2,1,4] [2,1,13,4]
>False

现在我已经这样做了,但我觉得效率低下:

prefix :: [Int] -> [Int] -> Bool
prefix (x:xs) (y:ys)
|   null xs                         =   True
|   x == y && head xs == head ys    =   True && prefix xs ys
|   head xs /= head ys              =   False

我希望它可以更有效地完成,并通过一些更好的模式匹配。可以吗?

【问题讨论】:

  • 捕捉缺失模式的一个好方法是使用-fwarn-incomplete-patterns 或只使用-Wall 运行GHC。通常,将{-# OPTIONS_GHC -Wall #-} 写在文件顶部。

标签: list haskell recursion boolean pattern-matching


【解决方案1】:

您根本不需要使用head 函数。这使比较次数增加了一倍。试试这个:

prefix :: [Int] -> [Int] -> Bool
prefix [] _ = True
prefix _ [] = False
prefix (x:xs) (y:ys)
  | x == y = prefix xs ys
  | otherwise = False

【讨论】:

  • 哦,我明白了,是的,它确实有效,我现在找到了一个我的实例没有,当我让第一个列表包含任何单个整数时,它将返回 true。您能解释一下您的解决方案中的(_:_) 部分吗?
  • (_:_) [] 匹配第一个列表长于第二个的情况,这意味着第一个永远不可能是第二个的前缀。 (代码实际上可以缩短为_ [],因为我们已经在第一个模式中匹配了一个空的第一个列表)
  • @GarethAllen-Stringer (x:xs) 在这种情况下,模式匹配列表的第一项 (x) 和尾部 (xs),请参阅 learnyouahaskell.com/syntax-in-functions
【解决方案2】:

Chad Gilbert 的解决方案可以非常精简:

prefix :: [Int] -> [Int] -> Bool
prefix [] _ = True
prefix (x:xs) (y:ys)
  | x == y = prefix xs ys
prefix _ _ = False

这不会影响性能,但它展示了一个语言特性:当一个模式上的所有守卫都失败时,该匹配将被放弃,匹配将恢复到下一个模式。

【讨论】:

    【解决方案3】:
     Prelude > let prefix [] _ = True
     Prelude |     prefix _ [] = False
     Prelude |     prefix (x:xs) (y:ys) = if ( x==y) then prefix xs ys else False
    

    例子:

      Prelude> prefix [1,3] []
      False
      Prelude> prefix [] [1,2,3]
      True
      Prelude> prefix [1,2] [1,2,3]
      True
    

    【讨论】:

      猜你喜欢
      • 2018-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-29
      • 1970-01-01
      • 2017-06-22
      • 2016-08-03
      相关资源
      最近更新 更多