optimize :: [Decl] -> [Decl]
optimize ds = do
  let used = evalState (runErrorT optimize') OptiState { decls = ds ++ builtIns,
                                                         scope = [],
                                                         checked = [] }
  -- we expect this to always be Right, maybe refactor?
  let Right names = used
      keep = "main" : (builtInNames ++ names)

  filter (\d -> case d of
             PDecl name _ -> name `elem` keep
             _ -> False) ds
optimize :: [Decl] -> [Decl]
optimize ds = do
  let used = evalState (runErrorT optimize') OptiState { decls = ds ++ builtIns,
                                                         scope = [],
                                                         checked = [] }
  -- we expect this to always be Right, maybe refactor?
  let Right names = used
      keep = "main" : (builtInNames ++ names)

  filter (\d -> case d of
             PDecl name _ -> name `elem` keep
             _ -> False) ds
optimize ds = do
  let used = evalState (runErrorT optimize') OptiState { decls = ds ++ builtIns,
                                                         scope = [],
                                                         checked = [] }
  -- we expect this to always be Right, maybe refactor?
  let Right names = used
      keep = "main" : (builtInNames ++ names)

  filter (\d -> case d of
             PDecl name _ -> name `elem` keep
             _ -> False) ds