Klasycznym przykładem czegoś łatwiejszego do wdrożenia z conduit
jest obecnie obsługa końca wejścia od źródła. Na przykład, jeśli chcesz spasować listę wartości i powiązać wynik w potoku, nie możesz tego zrobić w ramach pipes
bez tworzenia dodatkowego protokołu pod numerem pipes
. To jest właśnie to, co rozwiązuje biblioteka pipes-parse
. To inżynier protokół Maybe
na górze pipes
, a następnie definiuje wygodne funkcje do wprowadzania danych wejściowych z góry, zgodnie z tym protokołem.
Na przykład, mają funkcję onlyK
, który przyjmuje rurę i otacza wszystkie wyjścia w Just
, a następnie kończy się Nothing
:
onlyK :: (Monad m, Proxy p) => (q -> p a' a b' b m r) -> (q -> p a' a b' (Maybe b) m r)
Można również funkcję justK
, który określa funktorem z rur że są Maybe
-unaware do rur, które są Maybe
-aware dla wstecznej kompatybilności
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
A potem raz masz Producer
, który przestrzega tego protokołu, możesz użyć wielu różnych analizatorów, które są abstrakcyjne dla ciebie. Najprostszym z nich jest draw
:
draw :: (Monad m, Proxy p) => Consumer (ParseP a p) (Maybe a) m a
Pobiera wartość typu a
lub nie w transformatorze na ParseP
proxy jeśli przed zabrakło wejścia. Możesz także wziąć wiele wartości naraz:
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
... i kilka innych fajnych funkcji. Użytkownik nigdy nie musi w rzeczywistości bezpośrednio wchodzić w interakcję z końcem sygnału wejściowego.
Zwykle, gdy ludzie pytają o obsługę końcowych danych wejściowych, to, co naprawdę chcieli, było analizowanie, dlatego pipes-parse
tworzy ramki z błędami końca wejścia jako podzestawu parsowania.
Ciekawi mnie, jak ten protokół ma związek z kompozycją rur? Załóżmy, że mam potok 'readFileK', który odczytuje plik i wysyła' Nic' do sygnalizowania końca. Jeśli zrobię "(readFileK" file1 ">> readFileK" file2 ")> -> otherPipeK' to' otherPipeK' otrzyma 'Nothing' dwa razy? Z drugiej strony, jeśli mam plik 'readFileK'">> -> (pipe1K >> pipe2K) i dane wejściowe z pliku są wyczerpane podczas przetwarzania 'pipe1K', to' pipe2K' nigdy nie dowiaduje się, że dane wejściowe zostały już zapisane zubożony. –
Dlatego 'onlyK' jest oddzielnym kombinatorem, a zachowanie' Nothing' nie jest wbudowane w źródła. W ten sposób możesz łączyć wiele źródeł w jeden, na przykład 'onlyK (readFileS" file "> => readSocketS socket)'. Twój drugi przykład nie powoduje żadnych problemów. Jeśli 'pipe1K' zabraknie danych wejściowych, to zawiedzie w' ParseP' i 'pipe2K' nigdy nie będzie działać. Żaden z parsujących prymitywów nie może przekroczyć końca znacznika wejściowego. –