content: {-# LANGUAGE FlexibleInstances       #-}
  {-# LANGUAGE MultiParamTypeClasses   #-}
  {-# LANGUAGE UndecidableSuperClasses #-}
  {-# LANGUAGE TypeApplications        #-}
  
  import Data.List (span)
  
  -- A nested tree structure.
  -- Using `Maybe` allows encoding several zero-level items
  -- or irregular lists (see test example)
  data Nest a = Nest (Maybe a) [Nest a]
    deriving Eq
  
  instance Show a => Show (Nest a) where
    show (Nest (Just a) []) = show a
    show (Nest (Just a) s) = show a ++ show s
    show (Nest Nothing []) = "\"\""
    show (Nest Nothing s) = "\"\"" ++ show s
  
  -- An indented tree structure.
  type Indent a = [(Int, a)]
  
  -- class for isomorphic types
  class Iso b a => Iso a b where
    from :: a -> b
  
  -- A bijection from nested form to indent form
  instance Iso (Nest a) (Indent a) where
    from = go (-1)
      where
        go n (Nest a t) =
          case a of
            Just a -> (n, a) : foldMap (go (n + 1)) t
            Nothing -> foldMap (go (n + 1)) t
  
  -- A bijection from indent form to nested form
  instance Iso (Indent a) (Nest a) where
    from = revNest . foldl add (Nest Nothing [])
      where
        add t (d,x) = go 0 t
          where
            go n (Nest a s) =
              case compare n d of
                EQ -> Nest a $ Nest (Just x) [] : s
                LT -> case s of
                        h:t -> Nest a $ go (n+1) h : t
                        [] -> go n $ Nest a [Nest Nothing []]
                GT -> go (n-1) $ Nest Nothing [Nest a s]
  
        revNest (Nest a s) = Nest a (reverse $ revNest <$> s)
  
  -- A bijection from indent form to a string
  instance Iso (Indent String) String where
    from = unlines . map process
      where
        process (d, s) = replicate (4*d) ' ' ++ s
  
  -- A bijection from a string to indent form
  instance Iso String (Indent String) where
    from = map process . lines
      where
        process s = let (i, a) = span (== ' ') s
                    in (length i `div` 4, a)
  
  -- A bijection from nest form to a string via indent form
  instance Iso (Nest String) String where
    from = from @(Indent String) . from
  
  -- A bijection from a string to nest form via indent form
  instance Iso String (Nest String) where
    from = from @(Indent String) . from
  