欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

haskell - Monads - difference lists

程序员文章站 2024-01-10 14:54:07
...

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. 

相关标签: haskell