{-# OPTIONS -XMultiParamTypeClasses -XFlexibleInstances -XTypeSynonymInstances#-}

module Monocle.Utils where

import Data.Monoid

class (Monoid monoid) => MStack stack monoid where
    pop :: stack -> (stack, monoid)
    push :: monoid -> stack -> stack
    tappend :: monoid -> stack -> stack
    tcombine :: (monoid -> monoid) -> stack -> stack

instance (Monoid monoid) => MStack [monoid] monoid where
    pop s = case s of
        [] -> ([], mempty)
        x:xs -> (xs, x)
    push m s = m:s
    tappend m s = let (s', m') = pop s in push (mappend m m') s'
    tcombine f s = let (s', m') = pop s in tappend (f m') s'

class Printable a where
    str :: a -> String

data Wrap a = Wrap a

instance Printable String where
    str x = if (head x) == '*' then (tail x) else x

instance (Printable a, Printable b) => Printable (a, b) where
    str (x, y) = "(" ++ (str x) ++ ", " ++ (str y) ++ ")"

instance (Show a) => Printable (Wrap a) where
    str (Wrap x) = show x