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.
上一篇: JavaScript常用函数工具集
下一篇: 【JavaScript】常用工具函数