Question

Haskell's Text.JSON library uses an abstract data type called Result, it's basically their form of Maybe, but instead of Nothing, there's Error String. Anywho, I need to use liftIO to convert a function call returning an IO thing to a Result thing inside of my implementation of JSON.readJSON. I'm new to monad transformers and can't seem to implement liftIO for Result (I keep trying to construct the infinite type, according to ghci).

Any ideas?

Many thanks

EDIT

Sorry it's taken me so long to elaborate! I appreciate your help guys.

  readJSON (JSObject obj) = do text <- getVal obj "text"
                           user <- getVal obj "from_user"
                           iden <- getVal obj "id_str"
                           url <- (do if (length.extractURLs) text == 0
                                           then return ""
                                           else return $ head $ extractURLs text)
                           title <- liftIO (getSiteTitle url)
                           return $ 
                            Tweet 
                              NewsStory {
                                          title = "Twitter",
                                          desc = text,
                                          url = url,
                                          metric = 0,
                                          sourceURL = "twitter.com/" ++ user  ++ "/status/" ++ iden
                                        }

So the last line before return uses getSiteTitle to parse a website at that url for its title. However, that function returns a type of IO String and the compiler tells me it wants the it to be Result. Is this impossible?

Thanks again!

EDIT2

I've decided to eliminate the title from my data type and get it later on when inside an IO monad. Thanks for everyone's help! I've certainly learned from this issue.

Was it helpful?

Solution

You can't use IO inside of readJSON (without resorting to unsafePerformIO). liftIO is used when you have a stack of monad transformers with IO at bottom. Perhaps if you give more concrete information of what you are trying to achieve you'll be able to get a more useful answer :)

OTHER TIPS

What you want is impossible. In the json package, readJSON :: JSValue -> Result a. By definition, this is a pure function. Arguably, you could instantiate the result to something with IO inside, but then it would be impossible to fulfill showJSON :: a -> JSValue.

My solution? I'd give your data type a title :: Maybe String and then have a second pass in IO that filled in titles.

You don't say which particular JSON library your are using and there are dozens of them with similar names and namespaces...

Because you want to use IO to get the url you will have to divide your function into two functions, one in the JSON monad and one in the IO monad. Because you cannot "run" the IO monad, you will have to run the JSON monad within IO, here doAll is a further function to combine the two.

You will have to edit it a little to make it match the JSON library you are using - some of the type signatures are not filled out and I don't know what the "run" function and return types of your JSON monad:

-- This one is in the JSON monad...
-- The type sig needs fixing...
readJSON :: JSObject ?? -> GetJSON (String,String,String,String)
readJSON (JSObject obj) = do 
    text <- getVal obj "text"
    user <- getVal obj "from_user"
    iden <- getVal obj "id_str"
    url <- (do if (length.extractURLs) text == 0
               then return ""
               else return $ head $ extractURLs text)
    return (text,user,iden,url)

-- This one is in IO...
ioStep :: (String,String,String,String) -> IO TweetNewsStory
ioStep (text,user,iden,url) = do
  title <- getSiteTitle url
  return $ TweetNewsStory {
             title = "Twitter",
             desc = text,
             url = url,
             metric = 0,
             sourceURL = "twitter.com/" ++ user  ++ "/status/" ++ iden
           }


-- Type sig needs fixing...
-- The JSON library will provide something similar to
-- runJSON...
--
doAll :: JSObject ?? -> IO TweetNewsStort
doAll jsobj = 
    let ans = runJSON $ readJSON jsobj in 
     case ans of 
       Left err -> error $ err
       Right val -> ioStep val
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top