Haskell使用do-Block创建函数

时间:2015-12-09 16:50:47

标签: haskell

我有以下程序可以正常工作:

{-# 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.

如何解决我的问题?

1 个答案:

答案 0 :(得分:4)

现在这是一个monadic动作,所以使用monadic语法:

tags <- parseTags <$> getHTML "79.212.82.103"
--   ⩓             ⩓
--   ╰─────────────│────────── bind instead of 'let'
--                 ╰─────────────────── functor application

<$>只是中缀fmap。您也可以在getHTML的实现中使用它。