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. 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值