module L0216 where

data Stream0 a = Cons0 a (Stream0 a) deriving Show
data Stream1 a = Cons1 a (Stream1 a) | End1 deriving Show

instance Functor Stream0 where
 fmap f (Cons0 a b) = Cons0 (f a) (fmap f b)

a = Cons0 1 $ Cons0 2 $ Cons0 3 $ a
b = Cons0 4 $ Cons0 5 $ Cons0 6 $ b

interleave :: Stream0 a -> Stream0 a -> Stream0 a
interleave (Cons0 a1 a2) (Cons0 b1 b2) = Cons0 a1 $ Cons0 b1 $ interleave a2 b2

(+++) :: Stream1 a -> Stream1 a -> Stream1 a
End1 +++ s = s
(Cons1 a b) +++ s = Cons1 a (b +++ s)

c  = Cons1 1 $ Cons1 2 $ Cons1 3 End1
d  = Cons1 4 $ Cons1 5 $ Cons1 6 End1


data List a = Cons a (List a) | Empty deriving Show

e = Cons 1 $ Cons 2 $ Cons 3 $ Cons 4 $ Cons 5 Empty

f = Cons odd $ Cons even Empty

g = Cons (+1) Empty

h = Cons (*2) Empty

x0 = \x -> x

x1 = \x -> \y -> x.y

x2 = \x -> \y -> \z -> x.y.z

instance Functor List where
 fmap f Empty = Empty
 fmap f (Cons a b) = Cons (f a) (fmap f b)


conn :: List a -> List a -> List a
conn Empty b = b
conn (Cons a as) b = Cons a $ conn as b

listLength Empty = 0
listLength (Cons _ as) = 1 + listLength as
 
instance Applicative List where
 pure x = Cons x Empty

 Empty <*> _ = Empty
 _ <*> Empty = Empty
 (Cons a as) <*> (Cons b bs) = conn (fmap a (Cons b bs)) (as <*> Cons b bs)


