Il classico esempio di qualcosa di più semplice da implementare con conduit
attualmente sta gestendo la fine dell'input da upstream. Ad esempio, se si desidera piegare un elenco di valori e associare il risultato all'interno della pipeline, non è possibile farlo entro pipes
senza aver progettato un protocollo aggiuntivo su pipes
.
In realtà, questo è esattamente ciò che risolve la libreria pipes-parse
imminente. Progetta un protocollo Maybe
su pipes
e quindi definisce le funzioni utili per il disegno di input da monte che rispettano tale protocollo.
Ad esempio, si ha la funzione onlyK
, che prende un tubo e avvolge tutte le uscite di Just
e poi si conclude con un Nothing
:
onlyK :: (Monad m, Proxy p) => (q -> p a' a b' b m r) -> (q -> p a' a b' (Maybe b) m r)
Hai anche la funzione justK
, che definisce un funtore da tubi che sono Maybe
-unaware ai tubi che sono Maybe
-consapevoli per la compatibilità all'indietro
justK :: (Monad m, ListT p) => (q -> p x a x b m r) -> (q -> p x (Maybe a) x (Maybe b) m r)
justK idT = idT
justK (p1 >-> p2) = justK p1 >-> justK p2
E poi una volta che hai un Producer
che rispetta tale protocollo è possibile utilizzare una grande varietà di parser che si astraggono per il controllo Nothing
. Il più semplice è draw
:
draw :: (Monad m, Proxy p) => Consumer (ParseP a p) (Maybe a) m a
Si recupera un valore di tipo a
o fallisce nel trasformatore ParseP
proxy se a monte corto di ingresso. Puoi anche prendere più valori contemporaneamente:
drawN :: (Monad m, Proxy p) => Int -> Consumer (ParseP a p) (Maybe a) m [a]
drawN n = replicateM n draw -- except the actual implementation is faster
... e molte altre funzioni. L'utente non deve mai interagire direttamente con la fine del segnale di input.
Di solito quando le persone chiedono la gestione di fine input, ciò che volevano veramente era l'analisi, ed è per questo che i problemi di end-of-input dei frame pipes-parse
sono un sottoinsieme di analisi.
Sono curioso, come va questo protocollo insieme alla componibilità dei tubi? Supponiamo che io abbia una pipe 'readFileK' che legge un file e invia' Nothing' per segnalare la fine. Se faccio '(readFileK" file1 ">> readFileK" file2 ")> -> otherPipeK' quindi' otherPipeK' riceve 'Nothing' due volte? E d'altra parte, se ho 'readFileK" file' "> -> (pipe1K >> pipe2K) e l'input dal file è esaurito mentre' pipe1K' sta elaborando allora 'pipe2K' non apprende mai che l'input è già stato impoverito. –
Ecco perché 'onlyK' è un combinatore separato e il comportamento' Nothing' non è integrato nelle origini. In questo modo puoi combinare più fonti in una sola, ad esempio 'onlyK (readFileS" file "> => socket readSocketS)'. Il tuo secondo esempio non causa alcun problema. Se 'pipe1K' finisce l'input fallirà in' ParseP' e 'pipe2K' non funzionerà mai. Nessuno dei primitivi di analisi è in grado di superare la fine del marker di input. –