data Pila e = Vacia
              | Apilar e (Pila e)
              deriving Show


es_vacia :: Pila e -> Bool
primero :: Pila e -> e        -- se aplica a pilas no vacías
desapilar :: Pila e -> Pila e -- se aplica a pilas no vacías

es_vacia Vacia = True
es_vacia (Apilar e p) = False

primero (Apilar e p) = e
desapilar (Apilar e p) = p

-- Ejemplos

p0 = Vacia :: Pila Char
p1 = Apilar ']' p0
p2 = Apilar ')' p1
p3 = Apilar '}' p2
p4 = Apilar '>' p3

balanceo :: String -> Bool
balanceo as = balanceo_rec as Vacia

balanceo_rec :: String -> Pila Char -> Bool
balanceo_rec [] p = es_vacia p
balanceo_rec (a:as) p =
  if a `elem` ['(', '[', '{', '<']
  then balanceo_rec as (Apilar (derecho a) p)
  else if (a `elem` [')', ']', '}', '>']) 
       then (not (es_vacia p)) && (a == primero p) && (balanceo_rec as (desapilar p))
       else balanceo_rec as p

derecho :: Char -> Char
derecho '(' = ')'
derecho '[' = ']'
derecho '{' = '}'
derecho '<' = '>'