我正在使用 Haxl 库,并且正在尝试同时实现fetchHTML
:
import Data.Aeson
import Control.Concurrent.Async
import Control.Concurrent.QSem
import Haxl.Core
import Haxl.Prelude
instance DataSource' u HTTPRequest where
fetch = metaImplementation
data HTTPRequest a where
MakeRequest :: HTTPRequest Int
instance StateKey HTTPRequest where --Link HTTPRequest to State class
data State HTTPRequest =
HTTPRequestState {threadNum :: Int}
initialiseState :: Int -> IO (State HTTPRequest)
initialiseState threads = do
return HTTPRequestState {threadNum = threads}
metaImplementation :: State HTTPRequest -> Flags -> u -> [BlockedFetch' HTTPRequest] -> PerformFetch
metaImplementation HTTPRequestState{..} _flags user bfs =
AsyncFetch $ \inner -> do
sem <- newQSem threadNum
asyncs <- mapM (implementation sem) bfs
inner
mapM_ wait asyncs
implementation :: QSem -> BlockedFetch' HTTPRequest -> IO(Async())
implementation sem (BlockedFetch' request returnVal) =
async $ bracket_ (waitQSem sem) (signalQSem sem) $ do
e <- Control.Exception.try $
fetchHTML
case e of
Left ex -> putFailure returnVal (ex :: SomeException)
Right el -> putSuccess returnVal el
fetchHTML :: IO Int
fetchHTML = do
res <- get "https://example.com"
let resBody = res ^. responseBody
return (200)
makeHTTPRequest :: GenHaxl u Int --Perform concurrent fetches
makeHTTPRequest = dataFetch (MakeRequest)
我面临的问题是 HaxlBlockedFetch
是多态的:
BlockedFetch :: forall (r :: * -> *) a. r a -> ResultVar a -> BlockedFetch r
然而我希望fetchHTML
是单态的(只返回一个 Int):
fetchHTML :: IO Int
fetchHTML = do
res <- get "https://www.bbc.com"
let resBody = res ^. responseBody
return (200)
因此,当我尝试编译时出现以下错误:
Couldn't match expected type ‘a’ with actual type ‘Int’
‘a’ is a rigid type variable bound by
a pattern with constructor:
BlockedFetch :: forall (r :: * -> *) a.
r a -> ResultVar a -> BlockedFetch r,
in an equation for ‘implementation’
最初我认为我可以重新定义BlockedFetch
为:
data BlockedFetch' a where --Custom monomorphic implementation of BlockedFetch
BlockedFetch' :: HTTPRequest Int -> ResultVar Int -> BlockedFetch' HTTPRequest
但是,这需要一个新的实现DataSource
,以使其能够接收我的自定义BlockFetch'
:
class (DataSourceName r, StateKey r) => DataSource' u r where
fetch :: State r -> Flags -> u -> [BlockedFetch' r] -> PerformFetch
显然,这只会向后影响,需要我重新编写整个 Haxl 模块!
我的问题是:
1)有没有一种简单的方法来制作fetchHTML
多态?(我不太关心它返回什么,只是它完成后返回一些东西)
2) Haskell 程序员遇到此类问题时的一般方法是什么?