以下哪一项更好?

时间:2019-06-02 17:57:41

标签: performance haskell parallel-processing

因此,我有两个函数列表的实现,给定一个函数f :: Int -> a和一个数字n,它们应该产生列表[f 0, f 1, ..., f (n-1)]。我试图猜测在工作和跨度方面哪个更好。

tabulate1 :: (Int -> a) -> Int -> [a]
tabulate1 f n = tab (\x -> f (n - x)) n where
    tab _ 0 = []
    tab g n = let (x,xs) = (g n) ||| (tab g (n-1))
              in (x:xs)
tabulate2 :: (Int -> a) -> Int -> [a]
tabulate2 f n = tab f 0 (n-1) where
    tab f n m
        | n > m = []
        | n == m = [f n]
        | otherwise = let i = (n + m) `div` 2
                          (l, r) = (tab f n i) ||| (tab f i+1 m)
                      in (l ++ r)

第一个避免使用具有线性工作和跨度的(++),而第二个则并行计算两个子列表,但使用(++)

那么...哪个更好?

1 个答案:

答案 0 :(得分:1)

在Haskell中,时间和空间的复杂性通常是不平凡的,因为它是一种惰性语言。这意味着尽管一个函数可能是O(n!),但它的结果可能永远不需要,因此也就不会求值。或者像在这种情况下一样,如果您的函数返回一个列表,而其他函数只需要前三个元素,则仅对那些元素进行求值。

无论如何,您的函数只是map的特例,因此可以用更易读的方式对其进行编码:

tabulate f n = map f [0..n]

地图实现了折叠,可能是您可以获得的最优化的版本