使用非基元类型解决类型多义性



我很难弄清楚如何在以下代码中解决这种类型的歧义。我正在尝试使用库 Text.HTML.Scalpel 来获取所有具有满足正则表达式的 href 属性的元素。

{-# LANGUAGE OverloadedStrings #-}
import           Control.Monad
import qualified Data.ByteString.Char8  as B8
import           Data.List
import           Network.HTTP.Simple
import           Text.HTML.Scalpel.Core
import           Text.Regex.Posix
main :: IO ()
main = do
content <- fetchUrlBody "http://en.wikipedia.org/wiki/Lists_of_American_institutions_of_higher_education"
print $ scrapeStringLike content getStateListings
fetchUrl :: Request -> IO (Response B8.ByteString)
fetchUrl req = httpBS req
fetchUrlBody :: Request -> IO (B8.ByteString)
fetchUrlBody req = fmap getResponseBody $ fetchUrl req
getStateListings :: Scraper B8.ByteString [B8.ByteString]
getStateListings =
attrs "href" ("a" @: ["href" @=~ "[^/wiki/List_of_colleges_and_universities_in_]"])

给出以下错误:

Ambiguous type variable re0 arising from a use of @=~
prevents the constraint (RegexLike re0 String) from being solved.
Probable fix: use a type annotation to specify what re0 should be.
These potential instance exist:
instance RegexLike Regex String
-- Defined in Text.Regex.Posix.String
In the expression:
"href" @=~ "[^/wiki/List_of_colleges_and_universities_in_]"
In the second argument of (@:), namely
["href" @=~ "[^/wiki/List_of_colleges_and_universities_in_]"]
In the second argument of attrs, namely
("a"
@: ["href" @=~ "[^/wiki/List_of_colleges_and_universities_in_]"])
|
23 |   attrs "href" ("a" @: ["href" @=~ "[^/wiki/List_of_colleges_and_universities_in_]"])
|                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我已经尝试了各种方法,包括将麻烦的行更改为:

getStateListings :: Scraper B8.ByteString [B8.ByteString]
getStateListings =
attrs "href" ("a" @: ["href" @=~ (makeRegex "[^/wiki/List_of_colleges_and_universities_in_]" :: Regex)])

这似乎满足 RegexLike 约束中的 re0,但现在它也需要源类型。我不知道如何指定类型注释,以使正则表达式的类型为RegexLike Regex ByteString.新错误为:

Ambiguous type variable source0 arising from a use of makeRegex
prevents the constraint (RegexMaker
Regex CompOption ExecOption source0) from being solved.
Probable fix: use a type annotation to specify what source0 should be.
These potential instances exist:
instance RegexMaker Regex CompOption ExecOption B8.ByteString
-- Defined in Text.Regex.Posix.ByteString
instance RegexMaker Regex CompOption ExecOption String
-- Defined in Text.Regex.Posix.String
...plus two instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
In the second argument of (@=~), namely
(makeRegex "[^/wiki/List_of_colleges_and_universities_in_]" ::
Regex)
In the expression:
"href"
@=~
(makeRegex "[^/wiki/List_of_colleges_and_universities_in_]" ::
Regex)
In the second argument of (@:), namely
["href"
@=~
(makeRegex "[^/wiki/List_of_colleges_and_universities_in_]" ::
Regex)]
|
23 |   attrs "href" ("a" @: ["href" @=~ (makeRegex "[^/wiki/List_of_colleges_and_universities_in_]" :: Regex)])
|                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

咒语应该是

"href" @=~ (makeRegex ("^/wiki/List_of_colleges_and_universities_in_" :: String) :: Regex)

@=~的参数类型是多态的,因此您需要:: Regex来确定它。没有IsString Regex,所以你需要使用makeRegexmakeRegex是极其多态的。它的返回类型已经用:: Regex确定了,所以你需要给它的参数一个:: String来克服-XOverloadedStrings的多态性。

你可以用

regex :: String -> Regex
regex = makeRegex
"href" @=~ regex "^/wiki/List_of_colleges_and_universities_in_"

最新更新