{-# LANGUAGE RankNTypes, InstanceSigs, DeriveFunctor #-}
newtype Cont a = Cont {
    unCont :: forall r. (a -> r) -> r
}
(>>-) :: Cont a -> (a -> r) -> r
-- (Cont c) >>- f = c f
(>>-) = unCont
instance Functor Cont where
    fmap :: forall a b. (a -> b) -> Cont a -> Cont b
    fmap f (Cont c) = Cont $ \g -> c (\a -> g  $ f a)
    
instance Applicative Cont where
    pure :: forall a. a -> Cont a
    pure x = Cont $ \c -> c x
    
    (<*>) :: forall a b. Cont (a -> b) -> Cont a -> Cont b
    (Cont f) <*> (Cont c) = Cont $ \g -> g (f c)
    
    
instance Monad Cont where
    return = pure
    -- cx >>= f = Cont $ \k ->
    --     cx >>- \x ->
    --     (f x) >>- \fx ->
    --     k fx
    Cont x >>= f = Cont $ \k -> x $ \y ->
        let Cont h = f y
        in  h $ \ z -> k z
data Connection a = Connection a deriving (Show, Functor)
withConnection :: forall r. (Connection String -> r) -> r
withConnection f = f (Connection "MyConnection")
comp = fmap ("Modified" ++) <$> Cont withConnection
main = print $ unCont comp id