{-# LANGUAGE Safe #-}

module Data.InfList.Common
  ( nats
  , nats1
  , evens
  , odds
  , fibs
  , lucas
  , facts
  , pascalTriangle
  , bells
  , collatz
  ) where

import Data.InfList as I

-- Where is the idiomatic Haskell Nat type?

nats = I.iterate succ 0
nats1 = I.iterate succ 1
evens = I.iterate (+2) 0
odds = I.iterate (+2) 1
fibs = 0 ::: 1 ::: I.zipWith (+) fibs (I.tail fibs)
lucas = 2 ::: 1 ::: I.zipWith (+) lucas (I.tail lucas)
facts = 1 ::: I.mapAccumL (\prev i -> let i' = prev * i in (i',i')) 1 nats1

-- http://www.polyomino.f2s.com/david/haskell/hs/CombinatoricsCounting.hs.txt

nextPascal prev = Prelude.zipWith (+) ([0] ++ prev) (prev ++ [0])

pascalTriangle = I.iterate nextPascal [1]

bells = 1 ::: doBells ([1],[1]) where
   doBells (cs,bs) = b ::: doBells (cs',b:bs) where
     cs' = nextPascal cs
     b = sum (Prelude.zipWith (*) cs bs)

-- find one that doesn't contain 1!
collatz = I.iterate hotpo where
  hotpo n = let (half,rem) = divMod n 2 in if rem == 0 then half else n*3 + 1