Do tej pory użyłem zipSinks :: Monad m => Sink i m r -> Sink i m r' -> Sink i m (r, r')
, ale jest uważane za przestarzałe.Jaki jest preferowany sposób łączenia dwóch zlewów?
Odpowiedz
((Pakiet jest conduit-0.5.2.3. Cały module jest tylko dla wstecznej kompatybilności.))
[edit]
Więc moje proste monadycznego przypuszczenie (patrz niżej) wydaje się być zła, mimo że typy są poprawne. Teraz mogę tylko zgadywać, że odpowiedź brzmi:
Funkcje wymiany są nadal w fazie rozwoju, podobnie jak wszystkie rury i kanały kablowe oraz podobne koncepcje i biblioteki.
Będę czekać na następny interfejs API, aby rozwiązać to pytanie i nadal używać do tego czasu zipSink
. (może to była tylko niesłuszna.)
[/edit]
nie jestem, że znają z tego pakietu, ale nie byłoby zrobić tak samo jak ten?
zipSinks :: Monad m => Sink i m r -> Sink i m r' -> Sink i m (r, r')
zipSinks s1 s2 = (,) <$> s1 <*> s2
W końcu jest to Monad. (Functor, Applicative)
zipSinks :: Monad sink => sink r -> sink r' -> sink (r, r')
zipSinks s1 s2 = liftM2 (,) s1 s2
Typy są w porządku, ale nie semantyki. Twoja wersja 'zipSinks' będzie uruchamiać zlewy kolejno, a pierwsze zlew zostanie w pełni zużyte. – tymmym
Edit
Po uwzględnieniu tego, ja nie sądzę, że jest to możliwe przy obecnej wersji Data.Conduit. Rury nie są kategoriami, więc &&&
jest wykluczone. I nie ma sposobu, abym mógł wymyślić, by wyciągnąć wyniki z prądu, podawać je stopniowo do obu zlewów i zwierać, gdy kończy się pierwszy zlew. (Chociaż nie sądzę, że zwarcie w ten sposób działa, wydaje się, że byłoby to bardzo pożądane.) Z wyjątkiem oczywiście dopasowania do wzorca na obu zlewach (jak w pakiecie ma zipSinks
), ale to właśnie jesteśmy próbując tego uniknąć.
To powiedziawszy, chciałbym kochać, aby udowodnić, że jest źle tutaj.
To nie jest ładne, ale możesz to zrobić w sposób oczywisty.
Pierwsze import:
module Main where
import Control.Monad.Trans
import Data.Conduit
import qualified Data.Conduit.Binary as CB
import qualified Data.Conduit.List as CL
import qualified Data.Conduit.Text as CT
import qualified Data.Conduit.Util as CU
import Data.Maybe
import Data.Text (unpack)
Teraz zipSinks
. Zasadniczo chcesz utworzyć zlew, który pobiera dane wejściowe z kanału i przesyła je osobno do każdego zlewu podrzędnego. W tym przypadku użyłem do tego celu CL.sourceList
. Jeśli await
zwraca Nothing
, maybeToList
zwraca pustą listę, więc pochłaniacze podrzędne są również uruchamiane bez wprowadzania danych. Na koniec wynik każdego zlewu podrzędnego jest podawany do krotki.
zipSinks :: Monad m => Sink i m r -> Sink i m r' -> Sink i m (r, r')
zipSinks s1 s2 = do
l <- fmap maybeToList await
o1 <- lift $ CL.sourceList l $$ s1
o2 <- lift $ CL.sourceList l $$ s2
return (o1, o2)
Oto kilka przykładów użycia zipSinks
. Wygląda na to, że działa dobrze zarówno wewnątrz modelu IO
, jak i poza nim, a w kilku testach, które zrobiłem, wyjście dopasowuje wyjście zipped'
, utworzone przy użyciu starego zipSinks
.
doubleHead :: Monad m => Sink Int m (Maybe Int)
doubleHead = await >>= return . fmap (2*)
-- old version
zipped' :: Monad m => Sink Int m (Maybe Int, Maybe Int)
zipped' = CU.zipSinks CL.head doubleHead
-- new version
zipped :: Monad m => Sink Int m (Maybe Int, Maybe Int)
zipped = zipSinks CL.head doubleHead
fromList = CL.sourceList [7, 8, 9] $$ zipped
-- (Just 7, Just 14)
fromFile :: String -> IO (Maybe Int, Maybe Int)
fromFile filename = runResourceT $
CB.sourceFile filename
$= CB.lines
$= CT.decode CT.utf8
$= CL.map (read . unpack)
$$ zipped
-- for a file with the lines:
--
-- 1
-- 2
-- 3
--
-- returns (Just 1, Just 2)
Nice! (NB, możesz napisać 'oczekuj >> = return .fmap (2 *)' dla 'doubleHead', i podobnie,' l <- fmap maybeToList czekaj' zamiast używać 'input' w' zipSinks' .Ale jest, '' Data.Conduit.Internals "jest obcym importem?) – huon
Tak, zdałem sobie sprawę, że prawdopodobnie mogłem użyć funktorów w niektórych miejscach. W Haskell wciąż mam dość n00b, co niestety jest dla mnie zwykle edytorem drugiego przejścia. I tak, 'Data.Conduits.Internals' jest nieistotny. Początkowo szukałem przy użyciu 'sinkToPipe' z niego. Dzięki za wskazanie tych. Zaktualizuję odpowiedź. – Eric
Twoja wersja 'zipSinks' łączy tylko pierwsze elementy. Na przykład 'runResourceT $ CL.sourceList [1,2,3] $$ zipSinks (CL.take 2) (CL.take 2)' zwróci '([1], [1])', ale powinno '([1 , 2], [1,2]) ". – tymmym
- 1. Jaki jest preferowany sposób łączenia zależności za pomocą kontenera IoC?
- 2. Jaki jest preferowany sposób aktualizacji generatorów Yeoman?
- 3. Jaki jest preferowany sposób łączenia się z bazą danych PostgreSQL z PHP?
- 4. Jaki jest najbardziej elegancki sposób łączenia opcji?
- 5. Jaki jest preferowany sposób używania metod pomocniczych w Ruby?
- 6. Jaki jest preferowany sposób zwracania pustej tabeli w SQL?
- 7. Jaki jest preferowany sposób określić, czy procedura przechowywana istnieje
- 8. Jaki jest preferowany sposób korzystania z kolekcji równoległych w Scali?
- 9. Jaki jest preferowany sposób dołączania komunikatów o błędach do C++?
- 10. Jaki jest najlepszy sposób łączenia dwóch buforów środowiska wykonawczego systemu Windows?
- 11. Szyny: Jaki jest preferowany klejnot Mailchimp?
- 12. Jaki jest zalecany sposób łączenia się z MySQL z Go?
- 13. Jaki jest właściwy sposób wybierania i łączenia obiektów z LINQ?
- 14. Jaki jest właściwy sposób łączenia ze sobą 2 obiektów javascript?
- 15. Efektywny algorytm łączenia dwóch DAGów
- 16. Standardowy sposób łączenia dwóch tekstów Data.Text bez `mappend`
- 17. Algorytm łączenia dwóch maks. Stert?
- 18. Najszybsza metoda łączenia dwóch baz danych SQLite
- 19. Jaki jest najlepszy sposób dzielenia dwóch obiektów TimeSpan?
- 20. Jaki jest najszybszy sposób na połączenie dwóch list w python?
- 21. Jaki jest preferowany zestaw narzędzi RDF dla Ruby?
- 22. Jaki jest preferowany proces sprzedaży osobistego projektu/produktu?
- 23. Preferowany sposób tworzenia instancji w Go
- 24. Jaki jest preferowany sposób konstruowania obiektów w języku C#? Parametry lub właściwości konstruktora?
- 25. Jaki jest preferowany sposób uzyskania pełnej ścieżki serwera w widoku ASP.NET MVC?
- 26. Jaki jest preferowany sposób tworzenia szablonów serwisu i motywów za pomocą usługi Wicket?
- 27. Jaki jest preferowany sposób implementacji ustawień w aplikacji Ruby on Rails 3?
- 28. Jaki jest preferowany sposób uniknięcia zastrzyków SQL w Spark-SQL (w ulu)
- 29. Z MvvmCrossem, jaki jest preferowany sposób kopiowania wstępnie zapełnionej bazy danych SQLite
- 30. Jaki jest preferowany sposób zwracania pustej odpowiedzi JSON w Rails 3?
Jakie zachowanie, * dokładnie *, czy chcesz mieć "połączone" pochłaniacze? Próbowałem spojrzeć na starą dokumentację i implementację 'zipSinks', ale zachowanie nie jest łatwo dostrzegalne na pierwszy rzut oka. –
@DanBurton: 'zipSinks' pobiera dwa Zlewy i zwraca Zlew, który tworzy parę z wynikami odpowiednich Zlewów. Na przykład 'sizeCrc32Sink = zipSinks sizeSink crc32Sink' policzy rozmiar i sumę kontrolną. Mam to samo zachowanie, które opisał Oleg [tutaj] (http://okmij.org/ftp/Streams.html#1enum2iter). – tymmym
Ok Widzę; w zasadzie uzależnia oczekiwania i zasila wyjściowe wyjście do obu zlewów jednocześnie, w rodzaju rozwidlenia strumienia wejściowego na dwa. Dokumenty dla Data.Conduit.Util stwierdzają, że "istnieją teraz łatwiejsze sposoby radzenia sobie z ich przypadkami użycia", ale nie widzę prostszego sposobu na to użycie, ponieważ wymaga to zagnieżdżenia się w wewnętrznych elementach kanału do implementacji. –