Monad在StateT上下文中逃脱

时间:2015-06-27 14:36:07

标签: haskell state-monad aeson

我试图直接在StateT上堆放的IO内取回json Feed(通过Aeson)中的值:

{-# LANGUAGE DeriveGeneric #-}
module MyFeed where

import Data.Aeson
import Network.URI (parseURI, URI(..))
import Data.Maybe (fromJust)
import Data.Text (Text, unpack)
import Control.Monad.State
import Network.HTTP
import GHC.Generics
import Control.Applicative
import Network.HTTP.Conduit (simpleHttp)
import qualified Data.ByteString.Lazy as B

type Feed a = StateT MyIndex IO a

data MyIndex = MyIndex {
    index :: Int
}

data FooBar = Foo | Bar

data MyFeed = MyFeed {
    idx :: !Text,
    key :: !Text
    } deriving (Show,Generic)

instance FromJSON MyFeed
instance ToJSON MyFeed

getJSON :: String -> IO B.ByteString
getJSON url = simpleHttp url

getFeed :: String -> IO (Maybe MyFeed)
getFeed url = (decode <$> getJSON url) :: IO (Maybe MyFeed)

getIndex :: FooBar -> Feed MyIndex
getIndex fb = do
  cursor <- get
  let newCursor = case fb of
                            Foo -> do  myFeed <- liftIO $ getFeed "http://echo.jsontest.com/key/value/idx/1"
                                       let i = read $ unpack $ idx $ fromJust myFeed
                                       return $ cursor { index = i }

                            Bar -> return cursor
  put newCursor
  return newCursor

Foo案例中,我按预期获取了Feed,但是当返回所需的值时,我得到:

src/MyFeed.hs:47:10:
    Couldn't match expected type ‘MyIndex’
                with actual type ‘m0 MyIndex’
    Relevant bindings include
      newCursor :: m0 MyIndex (bound at src/MyFeed.hs:40:7)
    In the first argument of ‘return’, namely ‘newCursor’
    In a stmt of a 'do' block: return newCursor

Actual Type看起来仍处于Monad环境中(do {...})。有没有办法解决它或我使用错误的方法?

1 个答案:

答案 0 :(得分:0)

错误是由于我使用的事实:

let newCursor = case fb of

而不是

newCursor <- case fb of

因此,最终值永远不会从其monad上下文中“解开”。