2016-06-21 5 views
1

Как вы добавляете один ResumableSource к другому, если они явно не являются экземпляром Monad? Ниже приведен пример с игрушкой: a имеет ограничение Monad, а b не имеет его. Таким образом, мы можем добавить a's, но не b's:Добавление одного возобновляемого источника в другой

Prelude> import Data.Conduit 
Prelude Data.Conduit> import Data.ByteString as BS 
Prelude Data.Conduit BS> import Control.Monad.Trans.Resource 
Prelude Data.Conduit BS Control.Monad.Trans.Resource> let a = newResumableSource (yield (BS.pack [5])) -- this one has monad constraint 
Prelude Data.Conduit BS Control.Monad.Trans.Resource> :t a 
a :: Monad m => ResumableSource m ByteString 
Prelude Data.Conduit BS Control.Monad.Trans.Resource> :t a >> a 
a >> a 
    :: (Monad m, Monad (ResumableSource m)) => 
    ResumableSource m ByteString 
Prelude Data.Conduit BS Control.Monad.Trans.Resource> let b = undefined :: ResumableSource (ResourceT IO) ByteString 
Prelude Data.Conduit BS Control.Monad.Trans.Resource> :t b >> b 

<interactive>:1:3: 
    No instance for (Monad (ResumableSource (ResourceT IO))) 
     arising from a use of ‘>>’ 
    In the expression: b >> b 

Причина, я прошу, потому что у меня есть HTTP ResumableSource с тем же типом, как b выше, к которому я хотел бы предварять контент длину, перед подачей его в тонуть. В настоящее время, это выглядит следующим образом:

responseBody rsp $$+- sink 

Что я хотел бы изменить что-то вроде этого:

((newResumableSource (yield content-len)) >> (responseBody rsp)) $$+- sink 
+0

Обратите внимание на выведенный тип 'a >> a :: (Monad m, Monad (ResumableSource m)) => ResumableSource m ByteString'. Когда вы создаете экземпляр 'm', разработчик будет искать экземпляр« Monad (ResumableSource m) ». Поскольку 'ResumableSource' не имеет экземпляра' Monad', проверка типа завершится неудачей. Другими словами, невозможно использовать _use_ 'a >> a'. –

+0

ha, да, хорошая точка. Интересно, могу ли я просто сделать доход, чтобы потопить без раковины, заканчивающейся после завершения первого источника? Как 'yield content-len $$ sink; (responseBody rsp)) $$ + - sink'. – Sal

ответ

0

Хороший способ предварять первоначальное сообщение для ResumableSource, кажется, быть использование conduit, который дает это начальное сообщение, а затем становится сквозным. Здесь, я взял код из map трубопровода, чтобы создать такой канал:

passThruWInit :: Monad m => BS.ByteString -> C.Conduit BS.ByteString m BS.ByteString 
passThruWInit initMsg = do 
    C.yield initMsg -- generate initial message first 
    C.awaitForever $ C.yield -- now pass-through conduit for all messages 

Теперь мы обновляем responseBody rsp $$+- sink код, чтобы соответствовать его между:

responseBody rsp $=+ passThruWInit someInitMsg $$+- sink 

Конечным результатом является то, что someInitMsg это дало сначала, а затем передается содержимое responseBody. Таким образом, мы можем добавить длину контента и другие метаданные к возобновляемому телу ответа HTTP.