packages feed

Rattus-0.1.0.0: test/MemoryLeak.hs

{-# LANGUAGE TypeOperators #-}
module Main (module Main) where

import Rattus
import Rattus.Stream
import Rattus.ToHaskell

import qualified Prelude
import Prelude hiding ((<*>), map)

-- If we make pairs stable, we get a memory leak:
-- cannot do this anymore. We dissallow user-supplied Stable instances
-- instance (Stable a, Stable b) => Stable (a,b)


type Lazy a = ((),a)

{-# ANN module Rattus #-}


lazyAdd :: (a, Int) -> ((), Int) -> ((), Int)
lazyAdd = (\ (_,x) y -> fmap (+x) y )


scan3 :: (Stable a) => Box(a -> a -> a) -> Box (a -> Bool) -> a -> Str a -> Str a
scan3 f p acc (a ::: as) =  (if unbox p a then acc else a)
      ::: (delay (scan3 f p acc') <*> as)
  where acc' = unbox f acc a


-- Unless the strictification transformation is applied this function
-- will leak memory.
test1 :: Int -> Str (Int) -> Str (Int)
test1 = scan3 (box (+)) (box (== 0))



-- Unless the strictification transformation is applied this function
-- will leak memory. In addition, since it uses a lazy data structure,
-- it would also leak memory unless progres/promote evaluate to normal
-- form (using deepseq).
-- test2 :: Lazy Int -> Str (Lazy Int) -> Str (Lazy Int)
-- test2 = scan3 (box lazyAdd) (box (\ (_,x) -> x == 0))

-- If we Haskell's pair types, we get a memory leak:

leaky :: Str (Lazy Int) -> Str (Lazy Int)
leaky ((_,x):::xs) = ((),1) ::: delay (leaky  (fmap ((+) x) (hd (adv xs)) ::: (tl (adv xs))))


type Strict a = (():*a)

leakyStrict :: Str (Strict Int) -> Str (Strict Int)
leakyStrict ((_:*x):::xs) = (():*11) ::: delay (leakyStrict  (fmap ((+) x) (hd (adv xs)) ::: (tl (adv xs))))


buffer :: Stable a => Str a -> Str (List a)
buffer = scan (box (flip (:!))) Nil


{-# ANN recurse NotRattus #-}
recurse 0 (x : _) = print x
recurse n (_ : xs) = recurse (n-1) xs
recurse _ [] = putStrLn "the impossible happened: stream terminated"

{-# ANN main NotRattus #-}
main = do  
  let x =  fromStr $ test1 1 (toStr [1..])
  recurse 10000000 x
  
  let x = fromStr $ leakyStrict  (toStr $ Prelude.map (\ x-> (():*x)) [1..])
  recurse 10000000 x


  let x = fromStr $ leaky (toStr $ Prelude.map (\ x-> ((),x)) [1..])
  recurse 10000000 x
  
--   -- for comparison the Haskell code below does leak
--   let x = scan2 (+) (1::Int) [1,1..]
--   recurse 10000000 x

-- {-# ANN scan2 NotRattus #-}
-- scan2 :: (Int -> Int -> Int) -> Int -> [Int] -> [Int]
-- scan2 f acc (a : as) =  (if a == 0 then acc else 0) : scan2 f (f acc a) as