Naprawdę jestem zainteresowany ustaleniem, gdzie są różnice, a bardziej ogólnie, zidentyfikowaniem kanonicznych przypadków użycia, w których HLists nie mogą być używane (a raczej nie dają żadnych korzyści w porównaniu do zwykłych list).
(Zdaję sobie sprawę, że TupleN
w Scali jest 22 (wierzę) , podczas gdy potrzebna jest tylko jedna lista HList, ale nie jest to rodzaj różnicy pojęciowej, która mnie interesuje.)
W poniższym tekście zaznaczyłem kilka pytań. Właściwie może nie być konieczne odpowiadanie na nie, mają one raczej na celu wskazanie rzeczy, które są dla mnie niejasne, i ukierunkowanie dyskusji w określonych kierunkach.
Motywacja
Niedawno widziałem kilka odpowiedzi na SO, w których ludzie sugerowali użycie HLists (na przykład dostarczonych przez Shapeless ), w tym usuniętą odpowiedź na to pytanie . To dało początek tej dyskusji , która z kolei wywołała to pytanie.
Intro
Wydaje mi się, że hlisty są przydatne tylko wtedy, gdy znasz statycznie liczbę elementów i ich dokładne typy. Liczba w rzeczywistości nie jest kluczowa, ale wydaje się mało prawdopodobne, że kiedykolwiek będziesz musiał wygenerować listę z elementami różnych, ale statystycznie precyzyjnie znanych typów, ale nie znasz ich liczby. Pytanie 1: Czy mógłbyś w ogóle napisać taki przykład, np. W pętli? Moja intuicja jest taka, że posiadanie statycznie precyzyjnej listy hlist ze statycznie nieznaną liczbą dowolnych elementów (dowolnych względem danej hierarchii klas) po prostu nie jest kompatybilne.
HLists vs. krotki
Jeśli to prawda, tzn. Statycznie znasz liczbę i typ - Pytanie 2: dlaczego po prostu nie użyć n-krotki? Jasne, możesz bezpiecznie mapować i zawijać HList (co możesz również, ale nie typowo, zrobić w krotce za pomocą productIterator
), ale ponieważ liczba i typ elementów są znane statycznie, prawdopodobnie możesz po prostu uzyskać dostęp do elementów krotki bezpośrednio i wykonać operacje.
Z drugiej strony, jeśli funkcja, f
którą mapujesz na hlistę, jest tak ogólna, że akceptuje wszystkie elementy - Pytanie 3: dlaczego nie użyć jej za pośrednictwem productIterator.map
? Ok, jedna interesująca różnica może wynikać z przeciążenia metody: gdybyśmy mieli kilka przeciążonych f
, posiadanie silniejszej informacji o typie dostarczonej przez hlist (w przeciwieństwie do productIterator) mogłoby pozwolić kompilatorowi na wybranie bardziej szczegółowego f
. Nie jestem jednak pewien, czy to faktycznie zadziała w Scali, ponieważ metody i funkcje nie są takie same.
HLists i dane wejściowe użytkownika
Opierając się na tym samym założeniu, a mianowicie, że musisz znać liczbę i typy elementów statycznie - Pytanie 4: czy hlisty mogą być używane w sytuacjach, gdy elementy zależą od dowolnego rodzaju interakcji użytkownika? Np. Wyobraź sobie wypełnianie hlist elementów wewnątrz pętli; elementy są odczytywane skądś (interfejs użytkownika, plik konfiguracyjny, interakcja aktora, sieć), dopóki nie zostanie spełniony określony warunek. Jaki byłby typ listy hlist? Podobnie jest w przypadku specyfikacji interfejsu getElements: HList [...], która powinna działać z listami o statycznie nieznanej długości i która umożliwia komponentowi A w systemie uzyskanie takiej listy dowolnych elementów z komponentu B.
FunctionN
cechy nie potrafią wyodrębnić z arity: github.com/paulbutcher/ScalaMock/blob/develop/core/src/main/ ... github.com/paulbutcher/ScalaMock/blob / opracowania / core / src / main / ... Niestety nie jestem świadomy jakikolwiek sposób, że mogę korzystać z bezkształtnej, aby tego uniknąć, zważywszy, że muszę radzić sobie z „prawdziwym”FunctionN
sDla jasności, HList to w zasadzie nic innego jak stos
Tuple2
z nieco innym cukrem na wierzchu.Więc twoje pytanie dotyczy zasadniczo różnic między używaniem krotek zagnieżdżonych a krotek płaskich, ale te dwie są izomorficzne, więc ostatecznie nie ma żadnej różnicy poza wygodą, w której można używać funkcji biblioteki i której notacji można używać.
źródło
Jest wiele rzeczy, których nie można (dobrze) zrobić z krotkami:
Oczywiście możesz to wszystko zrobić za pomocą krotek, ale nie w ogólnym przypadku. Więc użycie HLists sprawia, że twój kod jest bardziej SUCHY.
źródło
Mogę to wyjaśnić w bardzo prostym języku:
Nazewnictwo krotki i listy nie jest istotne. HLists można nazwać jako HTuples. Różnica polega na tym, że w Scala + Haskell możesz to zrobić za pomocą krotki (używając składni Scala):
aby pobrać krotkę wejściową składającą się z dokładnie dwóch elementów dowolnego typu, dołączyć trzeci element i zwrócić w pełni wpisaną krotkę z dokładnie trzema elementami. Ale chociaż jest to całkowicie ogólne w stosunku do typów, musi jawnie określić długości wejścia / wyjścia.
To, co pozwala HList w stylu Haskell, to nadanie tej ogólnej długości, więc możesz dołączyć do dowolnej długości krotki / listy i odzyskać w pełni statycznie wpisaną krotkę / listę. Ta korzyść dotyczy również kolekcji o jednorodnym typie, w których można dołączyć liczbę int do listy dokładnie n wartości int i otrzymać listę, która jest zapisana statycznie tak, aby zawierała dokładnie (n + 1) liczb int bez jawnego określania n.
źródło