缺少Monadstate实例

时间:2016-08-08 00:25:32

标签: haskell monads state-monad

我正在尝试使用这个库构建一个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的实例呢?我怎么能解决这个问题?

1 个答案:

答案 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 >>=

另外,如果您不确定,那么老的括号总是在这里拯救:)

相关问题