我有以下程序可以正常工作:
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE ScopedTypeVariables #-}
module GPS where
import Network.Wreq
import Control.Lens
import Text.HTML.TagSoup
import Data.ByteString.Lazy
import Data.ByteString.Lazy.Char8
import Data.Strings
getStr :: Tag ByteString -> String
getStr tag@(TagText str) = Data.ByteString.Lazy.Char8.unpack str
getStr _ = ""
filterStr :: [Tag ByteString] -> [String]
filterStr [] = []
filterStr (t:r) = [getStr t] ++ filterStr r
main :: IO ()
main = do
r <- post "http://www.geocodeip.com" ["IP" := Data.ByteString.Lazy.Char8.pack "79.212.82.103"]
html <- r ^. responseBody
let tags = parseTags html
let tr = Prelude.head $ sections (~== ("<tr>" :: String)) tags
let tag = Prelude.filter isTagText tr
let text = filterStr tag
let ztext =Prelude.zip [0..] text
let nlat = Prelude.head $ Prelude.map fst . Prelude.filter (\(_, str) -> strEq str ("Latitude:" :: String)) $ ztext
let nlng = Prelude.head $ Prelude.map fst . Prelude.filter (\(_, str) -> strEq str ("Longitude:" :: String)) $ ztext
let lat = read (Prelude.head $ Prelude.map snd . Prelude.filter (\(n, _) -> n == nlat + 1) $ ztext) :: Double
let lng = read (Prelude.head $ Prelude.map snd . Prelude.filter (\(n, _) -> n == nlng + 1) $ ztext) :: Double
print lat
print lng
现在是有趣的部分 - 我想从这个“do-Block”中创建子功能,例如getHTML,getTags,makeText等....
所以我开始做以下事情:
getHTML :: String -> IO ByteString
getHTML ip = fmap (view responseBody) (post "http://www.geocodeip.com" ["IP" := Data.ByteString.Lazy.Char8.pack ip])
这应该替换我的do-Block的第一行和第二行,它应该得到HTML。这很好用,唯一的问题是它使用IO
返回一个类型,因此let tags = parseTags $ getHTML "79.212.82.103"
无效:
[1 of 1] Compiling GPS ( GPS.hs, interpreted )
GPS.hs:38:14:
No instance for (Text.StringLike.StringLike (IO ByteString))
arising from a use of ‘parseTags’
In the expression: parseTags
In the expression: parseTags $ getHTML "79.212.82.103"
In an equation for ‘tags’:
tags = parseTags $ getHTML "79.212.82.103"
GPS.hs:39:37:
No instance for (Text.StringLike.StringLike (IO ByteString))
arising from a use of ‘~==’
In the first argument of ‘sections’, namely
‘(~== ("<tr>" :: String))’
In the second argument of ‘($)’, namely
‘sections (~== ("<tr>" :: String)) tags’
In the expression:
Prelude.head $ sections (~== ("<tr>" :: String)) tags
GPS.hs:41:24:
Couldn't match type ‘IO ByteString’ with ‘ByteString’
Expected type: [Tag ByteString]
Actual type: [Tag (IO ByteString)]
In the first argument of ‘filterStr’, namely ‘tag’
In the expression: filterStr tag
Failed, modules loaded: none.
如何解决我的问题?
答案 0 :(得分:4)
现在这是一个monadic动作,所以使用monadic语法:
tags <- parseTags <$> getHTML "79.212.82.103"
-- ⩓ ⩓
-- ╰─────────────│────────── bind instead of 'let'
-- ╰─────────────────── functor application
<$>
只是中缀fmap
。您也可以在getHTML
的实现中使用它。