将单态函数与多态 Haxl 库一起使用?

Using monomorphic functions with polymorphic Haxl library?

我正在使用 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 是单态的(只有 return 一个 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 多态? (我不太关心它 return 是什么,只是它 return 是 某事 当它完成时)

2) Haskell 程序员遇到此类问题时的一般方法是什么?

The BlockedFetch 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 before