Search code examples
haskellstate-monadaeson

Monad escaping inside a StateT context


I am trying to get back a value that is in a json feed (via Aeson) directly inside a StateT stacked on IO:

{-# 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

In the Foo case I fetch the feed as expected but when the required value is returned I get:

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

The Actual Type looks still in a Monad context (do {...}). Is there a way to take it out or I am using a wrong approach?


Solution

  • The error was due to the fact I used:

    let newCursor = case fb of

    instead of

    newCursor <- case fb of

    For this reason the final value never get "unwrapped" from its monad context.