Использование библиотеки Req от Haskell со Scalpel для сохранения файлов на клиенте

#haskell

#haskell

Вопрос:

Я в 99% случаев использую Haskell / Scalpel scraper для извлечения тысяч файлов .gz пакетами и сохранения их локально на моем клиенте.

Теперь я пытаюсь взять фрагментированные [[String]] файлы и перевести их в IO, чтобы их можно было сохранить.

Я использую import Network.HTTP.Req .

 -- This is the argument for the downloadFiles function
chunkLinks :: IO [[String]]
chunkLinks = fmap (chunksOf 10) filterNonGz

-- THIS IS WHAT YOU EXECUTE 
downloadFile :: (MonadHttp m) => String -> m ()
downloadFile url = do
    -- Pull them into memory
    contents <- req GET (https (T.pack url)) NoReqBody bsResponse mempty

    -- Get the filename itself
    let fileName = head $ reverse $ T.splitOn "/" (T.pack url)

    -- Write them to the client (the filename will be the url)
    liftIO $ BSS.writeFile (dataDir    (T.unpack fileName)) (responseBody contents)


dataDir = "./Data/LODES/"

eatChunks :: (MonadHttp m) =>  m [()]
eatChunks = do
    (wtf :: [[String]]) <- liftIO $ (take (5) <$> chunkLinks)
    fmap concat $ liftIO $ mapM (liftIO . mapConcurrently (liftIO . downloadFile)) wtf
  

Я получаю сообщение об ошибке downloadFile в последней строке.

Ошибка:

Could not deduce (MonadHttp IO)
    arising from a use of ‘downloadFile’
  from the context: MonadHttp m
    bound by the type signature for:
               eatChunks :: forall (m :: * -> *). MonadHttp m => m [()]
    at /private/var/folders/70/kchtzk4j0hs398f95ywd78x00000gn/T/ghc-mod39229/UsCensusDataLodesScraper39228-2281.hs:195:1-37
  

Пожалуйста, извините за liftIO разбросанные по. Они предпринимают отчаянные попытки заставить это работать…

Кто-нибудь знает, что делать дальше?

Для справки, вывод chunkLinks выглядит следующим образом:

 [["https://lehd.ces.census.gov/data/lodes/LODES7/ak/od/ak_od_aux_JT00_2002.csv.gz","https://lehd.ces.census.gov/data/lodes/LODES7/ak/od/ak_od_aux_JT00_2003.csv.gz","https://lehd.ces.census.gov/data/lodes/LODES7/ak/od/ak_od_aux_JT00_2004.csv.gz","https://lehd.ces.census.gov/data/lodes/LODES7/ak/od/ak_od_aux_JT00_2005.csv.gz","https://lehd.ces.census.gov/data/lodes/LODES7/ak/od/ak_od_aux_JT00_2006.csv.gz","https://lehd.ces.census.gov/data/lodes/LODES7/ak/od/ak_od_aux_JT00_2007.csv.gz","https://lehd.ces.census.gov/data/lodes/LODES7/ak/od/ak_od_aux_JT00_2008.csv.gz","https://lehd.ces.census.gov/data/lodes/LODES7/ak/od/ak_od_aux_JT00_2009.csv.gz","https://lehd.ces.census.gov/data/lodes/LODES7/ak/od/ak_od_aux_JT00_2010.csv.gz","https://lehd.ces.census.gov/data/lodes/LODES7/ak/od/ak_od_aux_JT00_2011.csv.gz"], ...etc.
  

Комментарии:

1. Единственным экземпляром MonadHttp является Req . Способ выполнения Req действия — это runReq . Таким образом, вместо того, чтобы использовать liftIO для повышения вашего downloadFile от IO до чего-то, что не может сработать, потому что downloadFile не является IO действием, используйте runReq для понижения вашего downloadFile от чего-то до IO .

2. Я пробовал это, но, очевидно, я все еще делаю что-то не так: fmap concat $ mapM (mapConcurrently (runReq downloadFile)) wtf

3. Пытаюсь использовать defaultHttpConfig: fmap concat $ mapM (mapConcurrently (runReq . (defaultHttpConfig downloadFile))) wtf