`

haskell - Monads - difference lists

阅读更多

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. 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics