as We seen in previous example, where it is very low effecient to construct the list by appending, while if hte list is constructed in the wrong order, the performance can be worse, So if there is some effecient algorithm or datastructure then it would be perfect.
yes, there is such an data structure, and it is called "Difference List", actually it make s a function which does the list constructing (represent our lists as functions, so that list constructing becomes function constructing) . (it does not evaluated the constructed list immediately every time the difference list applied, but when the list is translated back to a list)
so, here is the DiffList wrapper's definition.
newtype DiffList a = DiffList { getDiffList :: [a] -> [a] }
and we have twoe method to convert DiffList from list to and from normal list.
toDiffList :: [a] -> DiffList a toDiffList xs = DiffList (xs++) fromDiffList :: DiffList a -> [a] fromDiffList (DiffList f) = f []
DiffList is an instance of the Monoid , and the difference is like this:
instance Monoid (DiffList a) where
mempty = DiffList (\xs -> [] ++ xs)
(DiffList f) `mappend` (DiffList g) = DiffList (\xs -> f (g xs))
the mempty is just the id function, and mappend is actually just function composition, so it becomes this:
ghci> fromDiffList (toDiffList [1,2,3,4] `mappend` toDiffList [1,2,3]) [1,2,3,4,1,2,3]
now, let's reimplement the gcd' method,
import Control.Monad.Writer
gcd' :: Int -> Int -> Writer (DiffList String) Int
gcd' a b
| b == 0 = do
tell (toDiffList ["Finished with " ++ show a])
return a
| otherwise = do
result <- gcd' b (a `mod` b)
tell (toDiffList [show a ++ " mod " ++ show b ++ " = " ++ show (a `mod` b)])
return result
and now let's review the logs.
ghci> mapM_ putStrLn . fromDiffList . snd . runWriter $ gcdReverse 110 34 Finished with 2 8 mod 2 = 0 34 mod 8 = 2 110 mod 34 = 8
How to prove that our DiffList is better performaned.
Comparing Performance.
the function that we will make is to count down from a number down to 0 ;
we will make two function, one with the normal list
finalCountDown :: Int -> Writer (DiffList String) ()
finalCountDown 0 = do
tell (toDiffList ["0"])
finalCountDown x = do
finalCountDown (x-1)
tell (toDiffList [show x])
and call this method.
ghci> mapM_ putStrLn . fromDiffList . snd . runWriter $ finalCountDown 500000 0 1 2 ...
and the other is the DiffList.
finalCountDown :: Int -> Writer [String] ()
finalCountDown 0 = do
tell ["0"]
finalCountDown x = do
finalCountDown (x-1)
tell [show x]
and we call this method...
ghci> mapM_ putStrLn . snd . runWriter $ finalCountDown 500000
we can see that the normal list counting down is very slow. while the former is really fast.
本文介绍了一种名为DifferenceList的数据结构,它通过将列表构造过程转化为函数构造,显著提高了列表操作的效率。尤其在需要频繁追加元素的情况下,DifferenceList相比传统列表表现出更好的性能。
406

被折叠的 条评论
为什么被折叠?



