defToNFA :: NFADef [ZOS] -> NFA Int Int
defToNFA (NFADef is ts fs) =
    let listsToVarMap = M.fromListWith (M.unionWith S.union)
        lts = LTS . M.map toBDDs . listsToVarMap $ trans
    in NFA lts (`inNEL` is) (`elem` fs)
  where
    toBDDs = MTBDD.or . map doUnit . M.toList
    doUnit = uncurry (MTBDD.unitWithVars S.empty)

    trans = NEL.toList ts >>= toTrans

    -- ss, ls and ts are all (non-empty) lists, so we use the list Monad to
    -- construct a single list of pairs from source states to a BDD map.
    toTrans (NFATransDef srcs ls trgs) = do
        s <- NEL.toList srcs
        l <- NEL.toList ls
        let converted = convertLabel l
        return (s, M.singleton converted (S.fromList . NEL.toList $ trgs))

    convertLabel = toVarList
      where
        toVarList = foldr go [] . zip [0..]

        -- Ignore stars, their variable's value doesn't matter
        go (pos, x) l = let s = case x of
                                    Zero -> Just False
                                    One -> Just True
                                    Star -> Nothing
                        in maybe l (\s' -> (pos, s') : l) s
defToNFA :: NFADef [ZOS] -> NFA Int Int
defToNFA (NFADef is ts fs) =
    let listsToVarMap = M.fromListWith (M.unionWith S.union)
        lts = LTS . M.map toBDDs . listsToVarMap $ trans
    in NFA lts (`inNEL` is) (`elem` fs)
  where
    toBDDs = MTBDD.or . map doUnit . M.toList
    doUnit = uncurry (MTBDD.unitWithVars S.empty)

    trans = NEL.toList ts >>= toTrans

    -- ss, ls and ts are all (non-empty) lists, so we use the list Monad to
    -- construct a single list of pairs from source states to a BDD map.
    toTrans (NFATransDef srcs ls trgs) = do
        s <- NEL.toList srcs
        l <- NEL.toList ls
        let converted = convertLabel l
        return (s, M.singleton converted (S.fromList . NEL.toList $ trgs))

    convertLabel = toVarList
      where
        toVarList = foldr go [] . zip [0..]

        -- Ignore stars, their variable's value doesn't matter
        go (pos, x) l = let s = case x of
                                    Zero -> Just False
                                    One -> Just True
                                    Star -> Nothing
                        in maybe l (\s' -> (pos, s') : l) s
defToNFA (NFADef is ts fs) =
    let listsToVarMap = M.fromListWith (M.unionWith S.union)
        lts = LTS . M.map toBDDs . listsToVarMap $ trans
    in NFA lts (`inNEL` is) (`elem` fs)
  where
    toBDDs = MTBDD.or . map doUnit . M.toList
    doUnit = uncurry (MTBDD.unitWithVars S.empty)

    trans = NEL.toList ts >>= toTrans

    -- ss, ls and ts are all (non-empty) lists, so we use the list Monad to
    -- construct a single list of pairs from source states to a BDD map.
    toTrans (NFATransDef srcs ls trgs) = do
        s <- NEL.toList srcs
        l <- NEL.toList ls
        let converted = convertLabel l
        return (s, M.singleton converted (S.fromList . NEL.toList $ trgs))

    convertLabel = toVarList
      where
        toVarList = foldr go [] . zip [0..]

        -- Ignore stars, their variable's value doesn't matter
        go (pos, x) l = let s = case x of
                                    Zero -> Just False
                                    One -> Just True
                                    Star -> Nothing
                        in maybe l (\s' -> (pos, s') : l) s