我正在使用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)我面临的问题是Haxl的BlockedFetch是多态的:
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程序员面对这类问题时的一般方法是什么?
发布于 2017-01-22 19:05:45
constructor存在量化a
data BlockedFetch r = forall a. BlockedFetch (r a) (ResultVar a)这意味着,创建BlockedFetch的人可以选择a是什么,但是在解压缩BlockedFetch a时保持抽象,不会与任何其他内容相统一。
但是,您确实可以访问r类型。通过选择r作为GADT,您可以将a约束为(一组)特定类型,并通过匹配GADT的构造函数来恢复该信息。您不必重写任何Haxl代码-它的设计允许您插入您自己的r!
在这个例子中,我看到您已经有了90%的实现方式:
data HttpRequest a where
MakeRequest :: HttpRequest Int因此,当您在MakeRequest构造函数上匹配时,您将获得a ~ Int的知识。
implementation :: QSem -> BlockedFetch' HTTPRequest -> IO(Async())
-- match the MakeRequest constructor
implementation sem (BlockedFetch' MakeRequest returnVal) =
-- as beforehttps://stackoverflow.com/questions/41793449
复制相似问题