-- | Traverse a recursive data structure without doing the same thing more
--   than once and return a Set of results. Similar to a fold.
--   Takes a function returning (result, candidates), then the initial set
recTraverseG :: (Ord a, Ord b)
             => (Set a -> (Set b, Set a)) -- ^ Function returning (result,
                                          -- candidates)
             -> Set a                     -- ^ Input
             -> Set b
recTraverseG = recTraverseG' S.empty
  where
    recTraverseG' done f x = if S.null cand'
                              then res
                              else res `S.union` recTraverseG' done' f cand'
      where (res, cand) = f x
            cand'       = cand S.\\ done'
            done'       = done `S.union` x

-- | Traverse a recursive data structure where results and candidates is the
--   same thing.
recTraverseG :: (Ord a, Ord b)
             => (Set a -> (Set b, Set a)) -- ^ Function returning (result,
                                          -- candidates)
             -> Set a                     -- ^ Input
             -> Set b
recTraverseG = recTraverseG' S.empty
  where
    recTraverseG' done f x = if S.null cand'
                              then res
                              else res `S.union` recTraverseG' done' f cand'
      where (res, cand) = f x
            cand'       = cand S.\\ done'
            done'       = done `S.union` x

-- | Traverse a recursive data structure where results and candidates is the
--   same thing.
recTraverseG = recTraverseG' S.empty
  where
    recTraverseG' done f x = if S.null cand'
                              then res
                              else res `S.union` recTraverseG' done' f cand'
      where (res, cand) = f x
            cand'       = cand S.\\ done'
            done'       = done `S.union` x

-- | Traverse a recursive data structure where results and candidates is the
--   same thing.