更改函数以支持IO String而不是String

时间:2016-02-24 21:42:48

标签: haskell io

我通过以下方式获得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字符串提供给该函数时理解错误,但到目前为止,它对我来说太复杂了:/

1 个答案:

答案 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操作/列表脊柱的结构。< /子>