 | Given a process p, find set of set of positions describing the conjunctive
-- normal form of the positions that    we need to go to.
-- For example: {{p1},{p2,p3}} means we need to go to p1 AND to either p2 or p3.
-- Correspond to f in Def. 15
-- TODO This is massively refactored code. Remove stuff that's commented out once everything works.
f :: (Show ann, MonadCatch m, Typeable ann) => (AnProcess ann) -> m (S.Set (S.Set ProcessPosition))
f  p -- corresponds to f within generate progressfunction.ml
    | blocking p = return $ ss []
    | (ProcessComb Parallel  _ pl pr) <- p =  do
                ll <- f pl
                lr <- f pr
                return $ S.union ([1] <..>  ll) ([2] <..>  lr)
    | otherwise = foldM combineWithRecursive
                            (S.singleton S.empty) -- accumulator, set of sets of position
                                                  -- not that the Singleton set of the empty set is
                                                  -- the neutral element with respect to combine
                                                  -- the empty set combined with anything gives an emptyset
                            (next0 p) -- list of p∈next^0(proc)
    -- | (ProcessNull _) <- p = return $ ss []
    -- | (ProcessAction Rep _ _ ) <-p = return $ ss []
    -- | (ProcessAction (ChIn _ _) _ _) <-p = return $ ss []
    -- | (ProcessComb comb _ pl pr) <- p 
    -- , isExclusive comb = foldM combineWithRecursive 
    --                         S.empty      -- accumulator, set of sets of position
    --                         (next0 proc) -- list of p∈next^0(proc) 
    -- | (ProcessComb NDC _ pl pr) <- p 
    -- , Just psl <- blocking0 pl, Just psr <- blocking0 pr = return $ ss [] 
    -- | (ProcessComb NDC _ pl pr) <- p
    -- , Just psl <- blocking0 pl, Nothing <- blocking0 pr = do
    --           lr <- f pr
    --           foldM combineWithRecursive 
    --                     ([2] <..>  lr) -- accumulator start with rhs positions
    --                     ([1] <.>  psl) -- fold over lhs positions
    -- | (ProcessComb NDC _ pl pr) <- p
    -- , Nothing <- blocking0 pl, Just psr <- blocking0 pr = do
    --           ll <- f pl
              -- foldM combineWithRecursive ([1] <..>  ll) ([2] <.>  psr)
    -- | (ProcessComb NDC _ pl pr) <- p
    -- , Nothing <- blocking0 pl, Nothing <- blocking0 pr =  do
    --             ll <- f pl
    --             lr <- f pr
    --             return $ combine ([1]  <..>  ll) ([2] <..>  lr)
    -- | (ProcessComb Parallel  _ pl pr) <- p =  do
    --             ll <- f pl
    --             lr <- f pr
    --             return $ S.union ([1] <..>  ll) ([2] <..>  lr) 
    -- | (ProcessAction _ _ p')  <- p = do l' <- f p'
    --                                     return $ [1] <..> l'
    where ss x = S.singleton ( S.singleton x) -- shortcut for singleton set of singleton set
          combineWithRecursive acc pos = do -- combine pss with positions from recursive call (case of nested NDCs)
                        proc'   <- (processAt p pos)
                        lpos <- f proc'
                        return $ combine (pos <..> lpos) acc 

-- | Compute progress function of proc
pf ::
f :: (Show ann, MonadCatch m, Typeable ann) => (AnProcess ann) -> m (S.Set (S.Set ProcessPosition))
f  p -- corresponds to f within generate progressfunction.ml
    | blocking p = return $ ss []
    | (ProcessComb Parallel  _ pl pr) <- p =  do
                ll <- f pl
                lr <- f pr
                return $ S.union ([1] <..>  ll) ([2] <..>  lr)
    | otherwise = foldM combineWithRecursive
                            (S.singleton S.empty) -- accumulator, set of sets of position
                                                  -- not that the Singleton set of the empty set is
                                                  -- the neutral element with respect to combine
                                                  -- the empty set combined with anything gives an emptyset
                            (next0 p) -- list of p∈next^0(proc)
    -- | (ProcessNull _) <- p = return $ ss []
    -- | (ProcessAction Rep _ _ ) <-p = return $ ss []
    -- | (ProcessAction (ChIn _ _) _ _) <-p = return $ ss []
    -- | (ProcessComb comb _ pl pr) <- p 
    -- , isExclusive comb = foldM combineWithRecursive 
    --                         S.empty      -- accumulator, set of sets of position
    --                         (next0 proc) -- list of p∈next^0(proc) 
    -- | (ProcessComb NDC _ pl pr) <- p 
    -- , Just psl <- blocking0 pl, Just psr <- blocking0 pr = return $ ss [] 
    -- | (ProcessComb NDC _ pl pr) <- p
    -- , Just psl <- blocking0 pl, Nothing <- blocking0 pr = do
    --           lr <- f pr
    --           foldM combineWithRecursive 
    --                     ([2] <..>  lr) -- accumulator start with rhs positions
    --                     ([1] <.>  psl) -- fold over lhs positions
    -- | (ProcessComb NDC _ pl pr) <- p
    -- , Nothing <- blocking0 pl, Just psr <- blocking0 pr = do
    --           ll <- f pl
              -- foldM combineWithRecursive ([1] <..>  ll) ([2] <.>  psr)
    -- | (ProcessComb NDC _ pl pr) <- p
    -- , Nothing <- blocking0 pl, Nothing <- blocking0 pr =  do
    --             ll <- f pl
    --             lr <- f pr
    --             return $ combine ([1]  <..>  ll) ([2] <..>  lr)
    -- | (ProcessComb Parallel  _ pl pr) <- p =  do
    --             ll <- f pl
    --             lr <- f pr
    --             return $ S.union ([1] <..>  ll) ([2] <..>  lr) 
    -- | (ProcessAction _ _ p')  <- p = do l' <- f p'
    --                                     return $ [1] <..> l'
    where ss x = S.singleton ( S.singleton x) -- shortcut for singleton set of singleton set
          combineWithRecursive acc pos = do -- combine pss with positions from recursive call (case of nested NDCs)
                        proc'   <- (processAt p pos)
                        lpos <- f proc'
                        return $ combine (pos <..> lpos) acc 

-- | Compute progress function of proc
f  p -- corresponds to f within generate progressfunction.ml
    | blocking p = return $ ss []
    | (ProcessComb Parallel  _ pl pr) <- p =  do
                ll <- f pl
                lr <- f pr
                return $ S.union ([1] <..>  ll) ([2] <..>  lr)
    | otherwise = foldM combineWithRecursive
                            (S.singleton S.empty) -- accumulator, set of sets of position
                                                  -- not that the Singleton set of the empty set is
                                                  -- the neutral element with respect to combine
                                                  -- the empty set combined with anything gives an emptyset
                            (next0 p) -- list of p∈next^0(proc)
    -- | (ProcessNull _) <- p = return $ ss []
    -- | (ProcessAction Rep _ _ ) <-p = return $ ss []
    -- | (ProcessAction (ChIn _ _) _ _) <-p = return $ ss []
    -- | (ProcessComb comb _ pl pr) <- p 
    -- , isExclusive comb = foldM combineWithRecursive 
    --                         S.empty      -- accumulator, set of sets of position
    --                         (next0 proc) -- list of p∈next^0(proc) 
    -- | (ProcessComb NDC _ pl pr) <- p 
    -- , Just psl <- blocking0 pl, Just psr <- blocking0 pr = return $ ss [] 
    -- | (ProcessComb NDC _ pl pr) <- p
    -- , Just psl <- blocking0 pl, Nothing <- blocking0 pr = do
    --           lr <- f pr
    --           foldM combineWithRecursive 
    --                     ([2] <..>  lr) -- accumulator start with rhs positions
    --                     ([1] <.>  psl) -- fold over lhs positions
    -- | (ProcessComb NDC _ pl pr) <- p
    -- , Nothing <- blocking0 pl, Just psr <- blocking0 pr = do
    --           ll <- f pl
              -- foldM combineWithRecursive ([1] <..>  ll) ([2] <.>  psr)
    -- | (ProcessComb NDC _ pl pr) <- p
    -- , Nothing <- blocking0 pl, Nothing <- blocking0 pr =  do
    --             ll <- f pl
    --             lr <- f pr
    --             return $ combine ([1]  <..>  ll) ([2] <..>  lr)
    -- | (ProcessComb Parallel  _ pl pr) <- p =  do
    --             ll <- f pl
    --             lr <- f pr
    --             return $ S.union ([1] <..>  ll) ([2] <..>  lr) 
    -- | (ProcessAction _ _ p')  <- p = do l' <- f p'
    --                                     return $ [1] <..> l'
    where ss x = S.singleton ( S.singleton x) -- shortcut for singleton set of singleton set
          combineWithRecursive acc pos = do -- combine pss with positions from recursive call (case of nested NDCs)
                        proc'   <- (processAt p pos)
                        lpos <- f proc'
                        return $ combine (pos <..> lpos) acc 

-- | Compute progress function of proc