import Control.Monad.Trans.State import Data.List (intercalate) import Control.Monad.IO.Class (liftIO) type TodoState a = StateT [Todo] IO a type Category = String data Todo = Todo { text :: String , categories :: [Category] } deriving (Show) addItem :: String -> [Category] -> TodoState () addItem txt cs = modify (Todo txt cs:) updateItem :: String -> String -> TodoState () updateItem old new = modify (map (\x -> if text x == old then x {text = new} else x)) viewList :: [Category] -> TodoState () viewList cs = do list <- get liftIO $ do putStrLn $ "# " ++ intercalate " & " cs mapM_ (putStrLn . ("- " ++) . text) $ filterCategory cs list putStr "\n" filterCategory :: [Category] -> [Todo] -> [Todo] filterCategory cs = filter (any (`elem` cs) . categories) runTodo :: TodoState () -> IO () runTodo = flip evalStateT [] main :: IO () main = runTodo $ do addItem "Go to work" ["Programming"] addItem "Create Sine Waves in C" ["Music", "Programming"] addItem "Play my synth" ["Music"] viewList ["Music"] updateItem "Create Sine Waves in C" "Create Sine Waves in Python" viewList ["Programming"] viewList ["Programming", "Music"]