我通过以下方式获得IO字符串:
import Data.Char
import Network.HTTP
import Text.HTML.TagSoup
openURL :: String -> IO String
openURL x = getResponseBody =<< simpleHTTP (getRequest x)
crawlType :: String -> IO String
crawlType pkm = do
src <- openURL url
return . fromBody $ parseTags src
where
fromBody = unwords . drop 6 . take 7 . words . innerText . dropWhile (~/= "<p>")
url = "http://pokemon.wikia.com/wiki/" ++ pkm
我希望通过以下方式解析其数据:
getType :: String -> (String, String)
getType pkmType = (dropWhile (== '/') $ fst b, dropWhile (== '/') $ snd b)
where b = break (== '/') pkmType
但是就像你看到的那样,getType
还不支持IO字符串。
我是IO新手,那么如何让它发挥作用? 我还尝试在将IO字符串提供给该函数时理解错误,但到目前为止,它对我来说太复杂了:/
答案 0 :(得分:7)
首先,强调: IO String
不是字符串。它是一个IO操作,当您在main
操作中的某个位置绑定它时,会产生类型String
的结果,但您不应该想到它作为某种“字符串类型的变化”。相反,它是 IO a
类型的特殊实例。
出于这个原因,您几乎肯定会不想要“更改功能以支持IO String
而不是String
”。 相反,您希望将此字符串接受功能原样应用于crawlType
操作的结果。正如我所说,这样的结果有String
类型,所以你在那里很好。例如,
main :: IO ()
main = do
pkm = "blablabla"
typeString <- crawlType pkm
let typeSpec = getType typeString
print typeSpec -- or whatever you wish to do with it.
您可以通过编写†
来省略typeString
变量
typeSpec <- getType <$> crawlType pkm
如果你愿意;这对应于过程语言中的内容
var typeSpec = getType(crawlType(pkm));
或者,您当然可以在crawlType
中包含解析权:
crawlType' :: String -> IO (String, String)
crawlType' pkm = do
src <- openURL url
return . getType . fromBody $ parseTags src
where
fromBody = unwords . drop 6 . take 7 . words . innerText . dropWhile (~/= "<p>")
url = "http://pokemon.wikia.com/wiki/" ++ pkm
† 如果您对<$>
operator的作用感到好奇:这不是内置语法,如do
/ <-
表示法。相反,它只是fmap
的中缀版本,您可以在列表专用版本map
中更好地了解它。列表[]
和IO
都是functors,这意味着您可以通过普通函数提取它们,仅更改元素/结果值,但不更改IO操作/列表脊柱的结构。< /子>