在 Haskell 中实现以线性时间运行的反向操作

发布于 2024-09-15 16:25:24 字数 476 浏览 8 评论 0原文

我刚刚学习 Haskell,如果我的问题很愚蠢,我很抱歉。我正在阅读 learnyouahaskell.com,现在正在读第 5 章“递归”。有一个标准“反向”函数的实现示例:

reverse' :: [a] -> [a]  
reverse' [] = []  
reverse' (x:xs) = reverse' xs ++ [x]  

但它似乎在 O(N^2) 时间内运行,而标准反向在 O(N) 时间内运行(我希望如此)。下面的代码说明了这一点:

sum (reverse [1,2..1000000]) -- runs pretty fast
sum (reverse' [1,2..1000000]) -- never finishes

因此,我开始思考如何更快地实现我自己的反向操作。用命令式语言很容易做到这一点。也许我需要后续章节中的一些更高级的材料来做到这一点?欢迎任何提示。

I'm just learning Haskell, so sorry if my question is stupid. I'm reading learnyouahaskell.com and now I'm at chapter 5 "Recursion". There's an example of implementation of standard 'reverse' function:

reverse' :: [a] -> [a]  
reverse' [] = []  
reverse' (x:xs) = reverse' xs ++ [x]  

But it seems that it runs in O(N^2) time, while the standard reverse runs in O(N) (I hope so). The following code illustrates this:

sum (reverse [1,2..1000000]) -- runs pretty fast
sum (reverse' [1,2..1000000]) -- never finishes

So, I started thinking how to implement my own reverse faster. It's pretty easy to do in imperative languages. Maybe I need some more advanced material from subsequent chapters to do this? Any hints are welcomed.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

伤痕我心 2024-09-22 16:25:24

它可以使用额外的累加器参数来高效实现,例如本例中 fac 的第二个参数:

factorial n = fac n 1
  where
    fac 0 r = r
    fac n r = fac (n-1) (r*n)

如果您只是想知道它在标准库中是如何完成的,您也可以 查看源代码

It can be implemented efficiently using an extra accumulator parameter, like the second parameter of fac in this example:

factorial n = fac n 1
  where
    fac 0 r = r
    fac n r = fac (n-1) (r*n)

If you just want to know how it's done in the standard library, you can also look at the source code.

混吃等死 2024-09-22 16:25:24

reverse前奏

您可以将其实现为:

reverse = foldl (flip (:)) []

reverse is defined in the Prelude.

You can implement it as:

reverse = foldl (flip (:)) []
森林迷了鹿 2024-09-22 16:25:24
reverse l =  rev l []
  where
    rev []     a = a
    rev (x:xs) a = rev xs (x:a)
reverse l =  rev l []
  where
    rev []     a = a
    rev (x:xs) a = rev xs (x:a)
懒的傷心 2024-09-22 16:25:24
foldl (\acc x -> x:acc) [] xs

其运行时间为 O(n)。这个想法非常简单 - 您采用一个空列表(累加器)并从上到下将元素传输到其中。

foldl (\acc x -> x:acc) [] xs

This runs in O(n). The idea is pretty simple - you take an empty list(accumulator) and transfer elements to it from top to bottom.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文