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中获取它。谢谢大家的帮助!我当然从这个问题中吸取了教训。
答案 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