为Text.JSON的Result类型编写liftIO实例

时间:2010-11-14 00:58:08

标签: json haskell monads monad-transformers

Haskell的Text.JSON库使用一个名为Result的抽象数据类型,它基本上是它们的Maybe形式,但它不是Nothing,而是Error String。 Anywho,我需要使用liftIO转换一个函数调用,将一个IO事件返回到我的JSON.readJSON实现中的Result事物。我是monad变换器的新手,似乎无法为Result实现liftIO(我继续尝试构造无限类型,根据ghci)。

有什么想法吗?

非常感谢

修改

对不起,我花了这么长时间来详细说明!我感谢你的帮助。

  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
                                        }

因此返回前的最后一行使用getSiteTitle来解析该网址上的网站的标题。但是,该函数返回一种IO字符串,编译器告诉我它希望它是Result。这不可能吗?

再次感谢!

EDIT2

我决定从我的数据类型中删除标题,然后在IO monad中获取它。谢谢大家的帮助!我当然从这个问题中吸取了教训。

3 个答案:

答案 0 :(得分:5)

你不能在readJSON中使用IO(不使用unsafePerformIO)。当你有一堆底部有IO的monad变换器时,会使用liftIO。也许如果你提供更多关于你想要达到的具体信息,你将能够获得更有用的答案:)

答案 1 :(得分:2)

你想要的是不可能的。在json包中,readJSON :: JSValue -> Result a。根据定义,这是一个纯函数。可以说,您可以将结果实例化为内部为IO的内容,但之后无法实现showJSON :: a -> JSValue

我的解决方案?我会给你的数据类型title :: Maybe String,然后在IO中填写第二个标题。

答案 2 :(得分:1)

你没有说你正在使用哪个特定的JSON库,并且有很多具有相似名称和名称空间的JSON库......

因为你想使用IO来获取url,你必须将你的函数划分为两个函数,一个在JSON monad中,一个在IO monad中。因为你无法“运行”IO monad,所以你必须在IO中运行JSON monad,这里doAll是另一个将两者结合起来的函数。

您必须稍微编辑它以使其与您正在使用的JSON库匹配 - 某些类型签名未填写且我不知道“运行”功能和返回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