A state alpha -> S.Set (S.Set state)
reachableStateSets nfa@NFA{..} = traverse S.empty $ S.singleton nfaStart
  where
    alphas = S.toList $ alphabets nfa
    traverse visited states
      | S.member states visited = visited
      | otherwise =
        foldl traverse (S.insert states visited) $ map (step nfa states) alphas

reachableStateSets :: (State state, Alphabet alpha)
                     => NFA state alpha -> S.Set (S.Set state)
reachableStateSets nfa@NFA{..} = traverse S.empty $ S.singleton nfaStart
  where
    alphas = S.toList $ alphabets nfa
    traverse visited states
      | S.member states visited = visited
      | otherwise =
        foldl traverse (S.insert states visited) $ map (step nfa states) alphas
reachableStateSets nfa@NFA{..} = traverse S.empty $ S.singleton nfaStart
  where
    alphas = S.toList $ alphabets nfa
    traverse visited states
      | S.member states visited = visited
      | otherwise =
        foldl traverse (S.insert states visited) $ map (step nfa states) alphas