module Stream where import Numeric.Natural (Natural) fibInit = (0, 1) fibGet (_, now) = now fibNext (prev, now) = (now, prev + now) -- Abstract type example using nested foralls. type Stream_A = forall r. (forall s. (s -> Natural) -> (s -> s) -> s -> r) -> r fibs_A :: Stream_A fibs_A user = user fibGet fibNext fibInit -- Abstract type example using existential types. Despite the "forall" word, it -- means exists. data Stream_E = forall s. Ctor (s -> Natural) (s -> s) s fibs_E :: Stream_E fibs_E = Ctor fibGet fibNext fibInit foldNat :: (a -> a) -> a -> Natural -> a foldNat s z n = go n where go 0 = z go n = s (go (n-1)) nth_fibs_A n = fibs_A (\get next init -> get (foldNat next init n)) nth_fibs_E n = case fibs_E of Ctor get next init -> get (foldNat next init n)