首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用具有多态Haxl库的单纯函数?

使用具有多态Haxl库的单纯函数?
EN

Stack Overflow用户
提问于 2017-01-22 16:38:22
回答 1查看 90关注 0票数 1

我正在使用Haxl库,并试图并发地实现fetchHTML

代码语言:javascript
复制
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是多态的:

代码语言:javascript
复制
BlockedFetch :: forall (r :: * -> *) a.  r a -> ResultVar a -> BlockedFetch r

然而,我希望fetchHTML是单一的(只返回一个Int):

代码语言:javascript
复制
fetchHTML :: IO Int 
fetchHTML = do
   res <- get "https://www.bbc.com"
   let resBody = res ^. responseBody 
   return (200)

因此,当我试图编译时,会得到以下错误:

代码语言:javascript
复制
  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如下:

代码语言:javascript
复制
data BlockedFetch' a where --Custom monomorphic implementation of BlockedFetch 
   BlockedFetch' :: HTTPRequest Int -> ResultVar Int -> BlockedFetch' HTTPRequest

但是,这需要一个新的DataSource实现,以使它能够接收我的自定义BlockFetch'

代码语言:javascript
复制
class (DataSourceName r, StateKey r) => DataSource' u r where 
   fetch :: State r -> Flags -> u -> [BlockedFetch' r] -> PerformFetch

显然,这只会影响向后,并要求我重写整个Haxl模块!

我的问题是:

1)是否有一种简单的方法使fetchHTML多态化?(我不太担心它会返回什么,只是它完成后会返回一些东西)

2) Haskell程序员面对这类问题时的一般方法是什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-01-22 19:05:45

constructor存在量化a

代码语言:javascript
复制
data BlockedFetch r = forall a. BlockedFetch (r a) (ResultVar a)

这意味着,创建BlockedFetch的人可以选择a是什么,但是在解压缩BlockedFetch a时保持抽象,不会与任何其他内容相统一。

但是,您确实可以访问r类型。通过选择r作为GADT,您可以将a约束为(一组)特定类型,并通过匹配GADT的构造函数来恢复该信息。您不必重写任何Haxl代码-它的设计允许您插入您自己的r

在这个例子中,我看到您已经有了90%的实现方式:

代码语言:javascript
复制
data HttpRequest a where
    MakeRequest :: HttpRequest Int

因此,当您在MakeRequest构造函数上匹配时,您将获得a ~ Int的知识。

代码语言:javascript
复制
implementation :: QSem -> BlockedFetch' HTTPRequest -> IO(Async())
                               -- match the MakeRequest constructor
implementation sem (BlockedFetch' MakeRequest returnVal) =
    -- as before
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41793449

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档