我正在尝试使用这个库构建一个slackbot:https://hackage.haskell.org/package/slack-api,只是为了学习更多的haskell,并希望最终了解monad -_-。
然后我有以下类型:
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
我用我的机器人运行:
initApp = lookupEnv "SLACK_API_TOKEN" >>=
\apiToken -> case apiToken of
Nothing -> throwM ApiTokenMissingException
Just t -> void $ Slack.runBot (Slack.SlackConfig t) runApp $ BotState emptyState
其中:
runApp :: Slack.Event -> Bot ()
runApp m@(Slack.Message cid uid body _ _ _) = sendMessage cid "GAH I CAN HAZ CHZBURGHER!"
这样运行正常,现在我希望添加更新系统状态的功能(通过递增计数器或其他方式)。
所以我将一个modifyState函数添加到我的Bot:
modifyState :: (AppState -> AppState) -> Bot ()
modifyState f = uses Slack.userState $ view appState >>=
\state -> modifying Slack.userState $ set appState $ f state
这打破了:
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’
鉴于modifying
的签名:
modifying :: MonadState s m => ASetter s s a b -> (a -> b) -> m ()
但是,查看Slack.userState
的文档:
userState :: forall s s. Lens (SlackState s) (SlackState s) s s Source
然后:
data SlackState s
... Constructor ...
Instances
Show s => Show (SlackState s)Source
MonadState (SlackState s) (Slack s)Source
那么为什么BotState
已经不是MonadState
的实例呢?我怎么能解决这个问题?
答案 0 :(得分:2)
$
运算符的固定性为0,而>>=
的固定性为1
,因此这样的代码可以正常工作:
main :: IO ()
main = do
putStrLn "hello world" >>= \_ -> putStrLn "hi"
但不是这一个:
main :: IO ()
main = do
putStrLn $ "hello world" >>= \_ -> putStrLn "hi"
它被解释为:
main :: IO ()
main = do
putStrLn ("hello world" >>= \_ -> putStrLn "hi")
要查看固定信息,请使用ghci
' :info
命令:
:info $
($) ::
forall (r :: ghc-prim-0.5.0.0:GHC.Types.RuntimeRep) a (b :: TYPE
r).
(a -> b) -> a -> b
-- Defined in ‘GHC.Base’
infixr 0 $
:info >>=
class Applicative m => Monad (m :: * -> *) where
(>>=) :: m a -> (a -> m b) -> m b
...
-- Defined in ‘GHC.Base’
infixl 1 >>=
另外,如果您不确定,那么老的括号总是在这里拯救:)