Jakich technik mogę użyć, aby konsekwentnie refaktoryzować kod, usuwając zależność od typów egzystencjalnych? Zazwyczaj są one używane do dyskwalifikacji niepożądanych konstrukcji twojego typu, a także do umożliwienia konsumpcji przy minimalnej wiedzy na temat danego typu (przynajmniej tak rozumiem).
Czy ktoś wymyślił prosty, spójny sposób na usunięcie polegania na nich w kodzie, który nadal zapewnia pewne korzyści? A przynajmniej jakieś sposoby na wślizgnięcie się w abstrakcję, która pozwala na ich usunięcie bez konieczności znacznej rezygnacji z kodu, aby poradzić sobie ze zmianą?
Możesz przeczytać więcej o typach egzystencjalnych tutaj („jeśli odważysz się…”).
functional-programming
haskell
type-systems
Petr Pudlák
źródło
źródło
Odpowiedzi:
Typy egzystencjalne nie są tak naprawdę uważane za złą praktykę w programowaniu funkcjonalnym. Myślę, że tym, co cię denerwuje , jest to, że jednym z najczęściej cytowanych zastosowań egzystencjalnych jest egzystencjalny antytyp typu egzystencjalnego , który zdaniem wielu osób jest złą praktyką.
Ten wzorzec jest często wykreślany jako odpowiedź na pytanie, w jaki sposób mieć listę heterogenicznie typowanych elementów, które wszystkie implementują tę samą klasę. Na przykład możesz chcieć mieć listę wartości, które mają
Show
instancje:Problem z takim kodem jest następujący:
AnyShape
jest zdobycie jego obszaru.AnyShape
konstruktora, aby wprowadzić jeden z typów kształtów do tegoAnyShape
typu.Jak się okazuje, ten fragment kodu tak naprawdę nie daje ci niczego, czego ten krótszy nie:
W przypadku klas opartych na wielu metodach ten sam efekt można ogólnie osiągnąć prościej, stosując kodowanie „rekord metod” - zamiast typowej klasy
Shape
definiuje się typ rekordu, którego polami są „metody” danegoShape
typu , i piszesz funkcje do przekształcania kręgów i kwadratów wShape
s.Ale to nie znaczy, że typy egzystencjalne są problemem! Na przykład w Rust mają one cechę zwaną obiektami cech, które ludzie często opisują jako cechy egzystencjalne nad cechą (wersje klas typu Rust). Jeśli egzystencjalne typy znaków są antypatternem w Haskell, czy to oznacza, że Rust wybrał złe rozwiązanie? Nie! Motywacja w świecie Haskell dotyczy składni i wygody, a nie zasady.
Bardziej matematycznym sposobem na przedstawienie tego jest wskazanie, że
AnyShape
typ z góry iDouble
są izomorficzne - istnieje między nimi „bezstratna konwersja” (no, z wyjątkiem precyzji zmiennoprzecinkowej):Mówiąc ściśle, nie zyskujesz ani nie tracisz żadnej mocy, wybierając jedną z nich. Co oznacza, że wybór powinien opierać się na innych czynnikach, takich jak łatwość użycia lub wydajność.
I pamiętaj, że typy egzystencjalne mają inne zastosowania poza tym przykładem list heterogenicznych, więc dobrze jest je mieć. Na przykład
ST
typ Haskella , który pozwala nam pisać funkcje, które są zewnętrznie czyste, ale wewnętrznie wykorzystują operacje mutacji pamięci, wykorzystuje technikę opartą na typach egzystencjalnych w celu zagwarantowania bezpieczeństwa w czasie kompilacji.Ogólna odpowiedź jest taka, że nie ma ogólnej odpowiedzi. Użycie typów egzystencjalnych można oceniać tylko w kontekście - a odpowiedzi mogą być różne w zależności od tego, jakie funkcje i składnia są dostępne w różnych językach.
źródło
Nie znam się zbyt dobrze na Haskell, więc postaram się odpowiedzieć na ogólną część pytania jako nieakademicki funkcjonalny programista C #.
Po przeczytaniu okazuje się, że:
Symbole wieloznaczne Java są podobne do typów egzystencjalnych:
Różnica między typami egzystencjalnymi Scali a symbolem wieloznacznym Javy na przykładzie
Symbole wieloznaczne nie są całkowicie zaimplementowane w języku C #: wariancja ogólna jest obsługiwana, ale wariancja witryny wywoływania nie jest
C # Generics: Symbole wieloznaczne
Możesz nie potrzebować tej funkcji codziennie, ale kiedy ją poczujesz (np. Musisz wprowadzić dodatkowy typ, aby wszystko działało):
Symbole wieloznaczne w ogólnych ograniczeniach C #
Na podstawie tych informacji typy egzystencjalne / symbole wieloznaczne są użyteczne, jeśli są poprawnie zaimplementowane i nie ma w nich nic złego jako takiego, ale prawdopodobnie można je niewłaściwie wykorzystywać, tak jak inne funkcje językowe.
źródło