I am attempting to build a slackbot using this library: https://hackage.haskell.org/package/slack-api, just to learn a little bit more haskell, and hopefully, finally understand monads -_-.
I then have the following types:
data BotState = BotState
{
_appState :: AppState
}
makeLenses ''BotState
type AppState = HM.Map String ChannelState
emptyState :: AppState
emptyState = HM.empty
data ChannelState = ChannelState
{ _counter :: Int}
type Bot = Slack.Slack BotState
and I run my bot with:
initApp = lookupEnv "SLACK_API_TOKEN" >>=
\apiToken -> case apiToken of
Nothing -> throwM ApiTokenMissingException
Just t -> void $ Slack.runBot (Slack.SlackConfig t) runApp $ BotState emptyState
where:
runApp :: Slack.Event -> Bot ()
runApp m@(Slack.Message cid uid body _ _ _) = sendMessage cid "GAH I CAN HAZ CHZBURGHER!"
This runs fine, now I wish to add the ability to update the system state (by incrementing the counter, or in other ways).
so I add a modifyState function to my Bot:
modifyState :: (AppState -> AppState) -> Bot ()
modifyState f = uses Slack.userState $ view appState >>=
\state -> modifying Slack.userState $ set appState $ f state
This breaks with:
No instance for (Control.Monad.State.Class.MonadState
(Slack.SlackState BotState) ((->) BotState))
arising from a use of ‘modifying’
In the expression: modifying Slack.userState
In the expression:
modifying Slack.userState $ set appState $ f state
In the second argument of ‘(>>=)’, namely
‘\ state -> modifying Slack.userState $ set appState $ f state’
Which makes sense given the signature for modifying
:
modifying :: MonadState s m => ASetter s s a b -> (a -> b) -> m ()
However, upon looking at the documentation for Slack.userState
:
userState :: forall s s. Lens (SlackState s) (SlackState s) s s Source
And then:
data SlackState s
... Constructor ...
Instances
Show s => Show (SlackState s)Source
MonadState (SlackState s) (Slack s)Source
So then why isn't the BotState
already an instance of MonadState
? How could I fix this?