-- FIXME Needs fairness for choice places
    -- stepPN :: (Show value, Monad m) => PN m value -> Marking value -> m (Bool, Marking value)
    stepPN :: PN SimFlow SimValue -> Marking SimValue -> SimFlow (Bool, Marking SimValue)
    stepPN (PN _ trans _) marking = do
        (progress, marking') <- foldM tryTrans (False, marking) $ DM.elems trans
        let unsafePlaces = filter (listAtLeastLength 2) $ DM.elems marking'
        when (not (null unsafePlaces)) $ do
            fail $ "Not safe " ++ show unsafePlaces
        return (progress, marking')
        where
            tryTrans (prevProgress, updatedMarking) trans
                | all inpCanFire inPlaces = do
                    fire <- case transCondition trans of
                        Nothing -> return True
                        Just cond -> do
                            v <- evalPNExpr inValues cond
                            let ret = case v of
                                  SimValue 1 [] -> True
                                  _ -> False
                            return ret
                    if fire
                        then do
                            -- outValues <- transAction trans trans inValues
                            outValues <- mapM (evalPNExpr inValues) $ transExprs trans
                            transReport trans inValues
                            when (length outValues /= length outPlaces) $ error $
                                "stepPN: transition `" ++ joinLabel (transLabel trans) ++ "' out token length mismatch"
                            return (True, pushPlaces poppedPlaces $ zip outPlaces outValues)
                        else return (prevProgress, updatedMarking)
                | otherwise = return (prevProgress, updatedMarking)
                where
                    inPlaces = transInPlaces trans
                    outPlaces = transOutPlaces trans

                    (poppedPlaces, inValues) = popPlaces updatedMarking inPlaces
                    -- can I take a token now (to cover choice places), and before this step (to cover places
                    --    which had a token added earlier this step)
                    inpCanFire placeNo = listAtLeastLength 1 (marking DM.! placeNo) &&
                        listAtLeastLength 1 (updatedMarking DM.! placeNo)
                    -- Use this for faster, not cycle number correct results
                    -- inpCanFire placeNo = listAtLeastLength 1 (updatedMarking DM.! placeNo)
stepPN :: PN SimFlow SimValue -> Marking SimValue -> SimFlow (Bool, Marking SimValue)
stepPN (PN _ trans _) marking = do
        (progress, marking') <- foldM tryTrans (False, marking) $ DM.elems trans
        let unsafePlaces = filter (listAtLeastLength 2) $ DM.elems marking'
        when (not (null unsafePlaces)) $ do
            fail $ "Not safe " ++ show unsafePlaces
        return (progress, marking')
        where
            tryTrans (prevProgress, updatedMarking) trans
                | all inpCanFire inPlaces = do
                    fire <- case transCondition trans of
                        Nothing -> return True
                        Just cond -> do
                            v <- evalPNExpr inValues cond
                            let ret = case v of
                                  SimValue 1 [] -> True
                                  _ -> False
                            return ret
                    if fire
                        then do
                            -- outValues <- transAction trans trans inValues
                            outValues <- mapM (evalPNExpr inValues) $ transExprs trans
                            transReport trans inValues
                            when (length outValues /= length outPlaces) $ error $
                                "stepPN: transition `" ++ joinLabel (transLabel trans) ++ "' out token length mismatch"
                            return (True, pushPlaces poppedPlaces $ zip outPlaces outValues)
                        else return (prevProgress, updatedMarking)
                | otherwise = return (prevProgress, updatedMarking)
                where
                    inPlaces = transInPlaces trans
                    outPlaces = transOutPlaces trans

                    (poppedPlaces, inValues) = popPlaces updatedMarking inPlaces
                    -- can I take a token now (to cover choice places), and before this step (to cover places
                    --    which had a token added earlier this step)
                    inpCanFire placeNo = listAtLeastLength 1 (marking DM.! placeNo) &&
                        listAtLeastLength 1 (updatedMarking DM.! placeNo)
                    -- Use this for faster, not cycle number correct results
                    -- inpCanFire placeNo = listAtLeastLength 1 (updatedMarking DM.! placeNo)
stepPN (PN _ trans _) marking = do
        (progress, marking') <- foldM tryTrans (False, marking) $ DM.elems trans
        let unsafePlaces = filter (listAtLeastLength 2) $ DM.elems marking'
        when (not (null unsafePlaces)) $ do
            fail $ "Not safe " ++ show unsafePlaces
        return (progress, marking')
        where
            tryTrans (prevProgress, updatedMarking) trans
                | all inpCanFire inPlaces = do
                    fire <- case transCondition trans of
                        Nothing -> return True
                        Just cond -> do
                            v <- evalPNExpr inValues cond
                            let ret = case v of
                                  SimValue 1 [] -> True
                                  _ -> False
                            return ret
                    if fire
                        then do
                            -- outValues <- transAction trans trans inValues
                            outValues <- mapM (evalPNExpr inValues) $ transExprs trans
                            transReport trans inValues
                            when (length outValues /= length outPlaces) $ error $
                                "stepPN: transition `" ++ joinLabel (transLabel trans) ++ "' out token length mismatch"
                            return (True, pushPlaces poppedPlaces $ zip outPlaces outValues)
                        else return (prevProgress, updatedMarking)
                | otherwise = return (prevProgress, updatedMarking)
                where
                    inPlaces = transInPlaces trans
                    outPlaces = transOutPlaces trans

                    (poppedPlaces, inValues) = popPlaces updatedMarking inPlaces
                    -- can I take a token now (to cover choice places), and before this step (to cover places
                    --    which had a token added earlier this step)
                    inpCanFire placeNo = listAtLeastLength 1 (marking DM.! placeNo) &&
                        listAtLeastLength 1 (updatedMarking DM.! placeNo)
                    -- Use this for faster, not cycle number correct results
                    -- inpCanFire placeNo = listAtLeastLength 1 (updatedMarking DM.! placeNo)