-- De-trealise Tree to Data
tree2data :: Data a => Tree String -> Maybe a
tree2data = gdefault `extR` atString
  where
    atString (Node x []) = Just x
    gdefault (Node x ts) = res
      where

    -- a helper for type capture
        res  = maybe Nothing (kids . fromConstr) con

    -- the type to constructed
        ta   = fromJust res

    -- construct constructor
        con  = readConstr (dataTypeOf ta) x

        -- recursion per kid with accumulation
        perkid ts = const (tail ts, tree2data (head ts))

        -- recurse into kids
        kids x =
          do guard (glength x == length ts)
             snd (gmapAccumM perkid ts x)

-- Trealise Data to Tree
tree2data :: Data a => Tree String -> Maybe a
tree2data = gdefault `extR` atString
  where
    atString (Node x []) = Just x
    gdefault (Node x ts) = res
      where

    -- a helper for type capture
        res  = maybe Nothing (kids . fromConstr) con

    -- the type to constructed
        ta   = fromJust res

    -- construct constructor
        con  = readConstr (dataTypeOf ta) x

        -- recursion per kid with accumulation
        perkid ts = const (tail ts, tree2data (head ts))

        -- recurse into kids
        kids x =
          do guard (glength x == length ts)
             snd (gmapAccumM perkid ts x)

-- Trealise Data to Tree
tree2data = gdefault `extR` atString
  where
    atString (Node x []) = Just x
    gdefault (Node x ts) = res
      where

    -- a helper for type capture
        res  = maybe Nothing (kids . fromConstr) con

    -- the type to constructed
        ta   = fromJust res

    -- construct constructor
        con  = readConstr (dataTypeOf ta) x

        -- recursion per kid with accumulation
        perkid ts = const (tail ts, tree2data (head ts))

        -- recurse into kids
        kids x =
          do guard (glength x == length ts)
             snd (gmapAccumM perkid ts x)

-- Trealise Data to Tree