【问题标题】:How to write a a reverse function in Haskell如何在 Haskell 中编写反向函数
【发布时间】:2017-05-12 12:23:05
【问题描述】:

所以,我知道,Haskell 中有一个内置函数可以反转列表,但我正在尝试编写自己的小函数,只是为了练习一些 Haskell。我想到了以下代码,遗憾的是它不起作用。你们能告诉我我做错了什么吗?

    rev :: [Int] -> [Int]
    rev [] = []
    rev [x] = last [x] : rev init [x]

【问题讨论】:

  • [x] 是一个包含单个元素(名为 x)的列表。 last [x] 只是 xinit [x][]。所以last [x] : rev init [x] 就是x : rev [],也就是x : [],也就是[x]。所以你的最后一行相当于rev [x] = [x]。但是你的主要问题是你没有一个包含多个元素的列表的案例。

标签: haskell reverse


【解决方案1】:

如果你想有效地做到这一点,我建议你使用累加器:

rev :: [a] -> [a]
rev xs = go xs []
   where
   go :: [a] -> [a] -> [a]
   go []     ys = ys
   go (x:xs) ys = go xs (x:ys)

go 函数在每一步从第一个列表 xs 中删除一个元素,并将其添加到第二个列表 ys 的前面。这类似于从堆栈中弹出并推送到另一个堆栈——这会颠倒顺序。

由于我们在每次递归调用中只使用固定的时间量,我们得到 O(n) 复杂度,其中 n 是列表长度。

相反,如果在每次递归调用中我们使用last 或附加... ++ [x],我们为每次调用支付 O(n),因此总体上为 O(n^2)。

【讨论】:

    【解决方案2】:

    你几乎拥有它。

    rev :: [Int] -> [Int]
    rev [] = []
    rev x = last x : rev (init x)
    

    解释:[x] 是一个包含 x 的列表,而你想直接用 x 操作

    ps。这是documentation for Data.List。还有记得import Data.List

    【讨论】:

    • 这就是我要找的!非常感谢!
    • 不客气!如果您认为答案很好地回答了您的问题,请记住接受答案(单击绿色勾号)。
    • 我认为这甚至无法解析 let :S
    • 感谢您发现错误。 let 被删除。
    • 我认为这不是一个高效的reverse 函数,因为很多调用昂贵的last 函数。我认为Valy's answer 展示了一种更好的方式来完成这项工作。
    【解决方案3】:

    好吧,你可以这样做:

    rev :: [Int] -> [Int]
    rev [] = []
    rev (x:l) = (rev l) ++ [x]
    

    第三行从列表中取出第一个元素,然后创建一个仅包含该元素的列表。这将附加到递归 rev l 调用的结果中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-07
      • 1970-01-01
      相关资源
      最近更新 更多