2016-08-08 14 views
0

私はこのライブラリを使用してslackbotを構築しようとしています:​​ちょっと勉強して、うまくいけば、ついにmonads -_-を理解しています。Monadstateのインスタンスがありません

私は、次の種類があります。

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 [email protected](Slack.Message cid uid body _ _ _) = sendMessage cid "GAH I CAN HAZ CHZBURGHER!" 

これは私が追加したい今、正常に動作システムの状態を更新する機能(カウンタをインクリメントする、または他の方法で)

ので、私は私のボットにmodifyState機能を追加します。

modifyState :: (AppState -> AppState) -> Bot() 
modifyState f = uses Slack.userState $ view appState >>= 
    \state -> modifying Slack.userState $ set appState $ f state 

これはで壊れる:

modifyingの署名与えられた意味を成し
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 :: 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 

それではなぜMonadStateのインスタンスすでにBotStateではないでしょうか?どうすればこの問題を解決できますか?

+2

のためにいつもここですBotState '、それは' MonadState(SlackState BotState)(( - >)BotState) 'を探しています。 '$'と '> ='のために優先順位の問題のようです - 明示的なかっこを試してみてください。 – user2407038

+0

あなたはそうだ、それは '' Slack.userState $ view appState'を使う '$'のせいだった。 'Slack.userState(view appState)'を使うように変更すると、問題が修正されます。私はそこで何が起こったのか理解したいですか?この特定の状況で '$'が期待どおりに動作しなかったのはなぜですか? ところで、助けてくれてありがとうございました。ポイントを集めたい場合は、答えとして書いてupvote/acceptを受け取りましょう:) –

+0

非常におおまかなことに、 '$'は括弧を末尾に追加すると考えることができます表現。だから、 'Slack.userState $ stuff1 >> = stuff2'は'意図されていないSlack.userState(stuff1 >> = stuff2) 'を使用しています。 'do'ブロックではこの問題は起こりません:' do state < - do Slack.userState $ view appState; Slack.userState $ set appState $ f state'を変更します。あなたが正しく字下げする限り( 'state < - 'と 'modifications'は同じ列で開始しなければなりません)、'; 'の代わりに改行を使うことができます – chi

答えて

2

$オペレータは>>=は固定性1を持っているので、このようなコードが動作するだろうが、固定性0を持っています

main :: IO() 
main = do 
    putStrLn "hello world" >>= \_ -> putStrLn "hi" 

でもないが、この1:

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

、古き良き括弧は、それがMonadState(SlackState BotState) `を探していませんので救助:)

関連する問題