-- | Converts any 'Foldable' container into the 'Closed' set of its
-- contents.
close :: (Hashable a, Eq a, Foldable t) => (a -> a) -> t a -> Closed a
close iter = Closed 0 iter . build Set.empty . toList where
  inserter :: (Hashable a, Eq a) => a -> (HashSet a, [a]) -> (HashSet a, [a])
  inserter a (set, fresh) | Set.member a set = (set, fresh)
                          | otherwise        = (Set.insert a set, a:fresh)
  build curr [] = Unchanging curr
  build curr as =
    ClosedF curr $ step (foldr inserter (curr, []) as)
  step (set, added) = build set (map iter added)

-- insert :: a -> Closed a -> Closed a
-- insert a Unchanging = 
-- insert a (Closed n iter set next) = 
close :: (Hashable a, Eq a, Foldable t) => (a -> a) -> t a -> Closed a
close iter = Closed 0 iter . build Set.empty . toList where
  inserter :: (Hashable a, Eq a) => a -> (HashSet a, [a]) -> (HashSet a, [a])
  inserter a (set, fresh) | Set.member a set = (set, fresh)
                          | otherwise        = (Set.insert a set, a:fresh)
  build curr [] = Unchanging curr
  build curr as =
    ClosedF curr $ step (foldr inserter (curr, []) as)
  step (set, added) = build set (map iter added)

-- insert :: a -> Closed a -> Closed a
-- insert a Unchanging = 
-- insert a (Closed n iter set next) = 
close iter = Closed 0 iter . build Set.empty . toList where
  inserter :: (Hashable a, Eq a) => a -> (HashSet a, [a]) -> (HashSet a, [a])
  inserter a (set, fresh) | Set.member a set = (set, fresh)
                          | otherwise        = (Set.insert a set, a:fresh)
  build curr [] = Unchanging curr
  build curr as =
    ClosedF curr $ step (foldr inserter (curr, []) as)
  step (set, added) = build set (map iter added)

-- insert :: a -> Closed a -> Closed a
-- insert a Unchanging = 
-- insert a (Closed n iter set next) = 