type PromptSegment = IO (Maybe String)
instance Monoid a => Monoid (IO a) where
mempty = return mempty
mappend = liftA2 (<>)
This behaves exactly how I want for my purposes.
For example:
ghci> let a = return $ Just "hello" :: IO Maybe String
ghci> let b = return $ Just " world" :: IO Maybe String
ghci> let c = return $ Nothing :: IO Maybe String
ghci> a `mappend` b `mappend` c
Just "hello world"
However, I'm pretty aware that maybe, for a different Monoid a => Monoid (IO a) instance other than a PromptSegment, maybe I wouldn't want mappend to behave the same way?? I feel like there's better way to do this than creating the orphan monoid instance above.
Current API design
currentDirectory :: PromptSegment
currentDirectory = Just <$> getCurrentDirectory
main :: IO ()
main = buildMainPrompt
[ bold . fgColor skyBlue <$> currentDirectory
, (fgColor deepSkyBlue3 . underline . bold <$> gitCurrentBranch)
<> (fgColor defaultDarkGreen . bold <$> gitRepositorySymbol "±")
<> gitStatusSegment
]
(fgColor red0 . bold <$> makePromptSegment " ➢ ")
(fgColor slateBlue0 . bold <$> makePromptSegment " λ» ")
gitStatusSegment :: PromptSegment
gitStatusSegment =
let unstagedSymbol = fgColor gold1 <$> gitUnstagedSymbol "✚"
stagedSymbol = fgColor orange <$> gitStagedSymbol "✎"
pushSymbol = fgColor red1 . bold <$> gitPushSymbol "↑"
in prependSpace <$> unstagedSymbol <> stagedSymbol <> pushSymbol
This is, of course, a work in progress, but the aim of the program is to create a DSL for defining cli prompt themes (starting with ZSH).This last code sample is mostly to serve the purpose of providing context to the question for why I would want to make IO (Maybe String) a Monoid. I'm wide open to harsh criticism - especially since this is my first attempt at writing a 'real' program in Haskell.
liftA2
/<*>
when they want to do this. It's marginally clearer and avoids orphan instances I guess.