2017-01-22 1 views
1

私はHaxlライブラリを使用していると私が同時にfetchHTMLを実装しようとしています:多型Hax1ライブラリーでの単形関数の使用?

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を望みますmonomorphic(intのみを返す):

fetchHTML :: IO Int 
fetchHTML = do 
    res <- get "https://www.bbc.com" 
    let resBody = res ^. responseBody 
    return (200) 

私は次のようになる私がコンパイルしようとROR:

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)この種の問題に直面したとき、ハスケルプログラマーの一般的なアプローチは何ですか?

答えて

3

The BlockedFetch constructorは、存在a定量化:

data BlockedFetch r = forall a. BlockedFetch (r a) (ResultVar a) 

これが作成されます誰BlockedFetchaが何であるかを選択するようになることを意味するが、BlockedFetchaが抽象的に保たれ、何か他のもので統一しません開梱時。

ただし、rタイプにアクセスできます。 rをGADTとして選択すると、aを特定のタイプの(1つの)タイプに制限し、GADTのコンストラクタを照合することでその情報を復元できます。あなたはHaxlコードを書き直す必要はありません - それはあなた自身のrを差し込めるように設計されています!この場合

、私はあなたがすでにそこに道の90%を持っていることを確認:あなたはMakeRequestコンストラクタに一致したときにあなたがa ~ Intという知識を得る

data HttpRequest a where 
    MakeRequest :: HttpRequest Int 

を。

implementation :: QSem -> BlockedFetch' HTTPRequest -> IO(Async()) 
           -- match the MakeRequest constructor 
implementation sem (BlockedFetch' MakeRequest returnVal) = 
    -- as before 
+0

私の編集は大丈夫ですか? –

+0

@BabraCunninghamいいえ:MakeRequestコンストラクタ内のパラメータと一致するようにしたバージョンを書きました( 'BlockedFetch '(MakeRequest int)returnVal)' 'MakeRequest'は空のコンストラクタです –

+0

I see!実装を 'implementation sem(BlockedFetch(MakeRequest)returnVal)=' 'に変更しました。"これはMakeRequestの "match"の意味ですか? –