I've written a simple command line todo-list in Haskell.
The full code can be found here. However, given people's time constraints, I have selected three verbose functions for review.
program :: StateT TodoList IO () program = do StateT $ \xs -> do (choice,_) <- runStateT requestChoice xs (_,xs') <- runStateT (parseChoice choice) xs runStateT printList xs' runStateT program xs' main = runStateT program 
- Am I repeating myself too much by extracting the monads using
- Is there a better way to structure the main program?
parseChoice :: Text -> StateT TodoList IO () parseChoice choice | first == "add" = addItem $ TodoItem second third | first == "remove" = removeItem $ parseInt second | first == "save" = saveList second | first == "load" = loadList second | first == "quit" = StateT $ \_ -> exitSuccess | otherwise = invalidChoice first where args = split (=='|') (toLower choice) first = head args second = if length args > 1 then args !! 1 else "" third = if length args > 2 then args !! 2 else ""
- Am I using too many guards?
removeItem :: Maybe Int -> StateT TodoList IO () removeItem mn = StateT remove where remove = \xs -> case mn of Just n -> if n <= length xs - 1 then return ((),removeAt n xs) else do S.putStrLn "Index too large" return ((),xs) Nothing -> do S.putStrLn "Invalid index entered" return ((),xs)
- Which parts are un-idiomatic?
- Which parts are superfluous?
- Should I decompose these longer functions into smaller functions that do less?
- How else can I improve this code?