将单态函数与多态 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
我正在使用 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