W Internecie można znaleźć:
Wyższy rodzaj == typ konstruktora?
class AClass[T]{...} // For example, class List[T]
Niektórzy twierdzą, że jest to typ bardziej uporządkowany, ponieważ streszcza typy, które byłyby zgodne z definicją.
Wyższe typy pokrewne to typy, które pobierają inne typy i konstruują nowy typ
Są one jednak znane również jako konstruktor typów . (Na przykład w Programowaniu w Scali ).
Wyższy rodzaj == konstruktor typu, który bierze konstruktor typu jako parametr typu?
W artykule Generics of a Highe Kind można przeczytać
... typy, które wyodrębniają ponad typy, które wyodrębniają ponad typy („typy lepiej dobrane”) ... ”
co sugeruje to
class XClass[M[T]]{...} // or trait YTrait[N[_]]{...} // e.g. trait Functor[F[_]]
jest rodzajem wyższego rodzaju.
Mając to na uwadze, trudno jest rozróżnić konstruktor typu , typ o wyższym typie i konstruktor typu, który przyjmuje konstruktory typu jako parametr typu , a zatem pytanie powyżej.
Odpowiedzi:
Pozwolę sobie nadrobić zaległości w tym zamieszaniu, wprowadzając z pewnym niedowierzaniem. Lubię używać analogii do poziomu wartości, aby to wyjaśnić, ponieważ ludzie są bardziej zaznajomieni z tym.
Konstruktory wartości są zwykle nazywane „funkcjami” lub „metodami”. O tych „konstruktorach” mówi się również, że są „polimorficzne” (ponieważ można je stosować do konstruowania „elementów” o różnym „kształcie”) lub „abstrakcjach” (ponieważ abstrakcyjne są to, co różni się między różnymi instancjami polimorficznymi).
W kontekście abstrakcji / polimorfizmu pierwszeństwo odnosi się do „jednorazowego użycia” abstrakcji: raz abstraktujesz nad typem, ale sam ten typ nie może abstrakcji nad niczym. Generics Java 5 są pierwszego rzędu.
Interpretacja powyższych charakterystyk abstrakcji pierwszego rzędu to:
Aby podkreślić, że nie ma w tym żadnej abstrakcji (myślę, że można to nazwać „zerowym porządkiem”, ale nigdzie go nie widziałem), na przykład wartość
1
lub typString
, zwykle mówimy, że coś jest „właściwą” wartością lub typem.Właściwa wartość jest „natychmiast użyteczna” w tym sensie, że nie czeka na argumenty (nie jest nad nimi abstrakcyjna). Pomyśl o nich jako o wartościach, które możesz łatwo wydrukować / sprawdzić (serializacja funkcji to oszustwo!).
Właściwy typ to typ, który klasyfikuje wartości (w tym konstruktory wartości), konstruktory typów nie klasyfikują żadnych wartości (najpierw należy je zastosować do argumentów odpowiedniego typu, aby uzyskać odpowiedni typ). Aby utworzyć instancję typu, konieczne (ale niewystarczające) jest, aby był on właściwym typem. (Może to być klasa abstrakcyjna lub klasa, do której nie masz dostępu).
„Nadrzędny porządek” jest po prostu ogólnym terminem, który oznacza wielokrotne stosowanie polimorfizmu / abstrakcji. Oznacza to to samo dla typów i wartości polimorficznych. Konkretnie, abstrakcja wyższego rzędu abstraktuje nad czymś, co abstraktuje nad czymś. W przypadku typów termin „bardziej uprzywilejowany” jest specjalną wersją bardziej ogólnego „wyższego rzędu”.
Tak więc wersja naszej charakteryzacji wyższego rzędu staje się:
Zatem „wyższy porządek” oznacza po prostu, że kiedy mówisz „abstrakcja nad X”, naprawdę masz na myśli! To,
X
co jest abstrakcyjne, nie traci własnych „praw do abstrakcji”: może abstrakcji wszystkiego, co chce. (Nawiasem mówiąc, używam tutaj czasownika „streszczenie”, aby pominąć coś, co nie jest niezbędne do zdefiniowania wartości lub typu, aby użytkownik mógł je zmienić / podać jako argument jako argument .)Oto kilka przykładów (zainspirowanych pytaniami Lutza wysłanymi e-mailem) prawidłowych wartości i typów pierwszego i wyższego rzędu:
Gdzie używane klasy zostały zdefiniowane jako:
Aby uniknąć pośrednictwa poprzez definiowanie klas, musisz w jakiś sposób wyrazić anonimowe funkcje typu, które nie są wyrażalne bezpośrednio w Scali, ale możesz używać typów strukturalnych bez nadmiernego nakładu składniowego (
#λ
styl jest spowodowany https://stackoverflow.com / users / 160378 / retronym afaik ):W niektórych hipotetycznych przyszłych wersjach Scali, które obsługują anonimowe funkcje typu, możesz skrócić ten ostatni wiersz z przykładów do:
(Osobiście żałuję, że kiedykolwiek mówiłem o „typach lepszych”, to w końcu są to tylko typy! Gdy absolutnie potrzebujesz ujednoznacznić, sugeruję powiedzenie takich rzeczy, jak „parametr konstruktora typu”, „członek konstruktora typu” lub „alias konstruktora typów”, aby podkreślić, że nie mówimy tylko o odpowiednich typach).
ps: Aby jeszcze bardziej skomplikować sprawy, „polimorficzny” jest niejednoznaczny w inny sposób, ponieważ typ polimorficzny oznacza czasami typ uniwersalnie skwantyfikowany, taki jak
Forall T, T => T
, który jest właściwym typem, ponieważ klasyfikuje wartości polimorficzne (w Scali ta wartość może być zapisane jako typ konstrukcyjny{def apply[T](x: T): T = x}
)źródło
(Ta odpowiedź jest próbą udekorowania odpowiedzi Adriaan Maurów przez pewne informacje graficzne i historyczne.)
Wyższe rodzaje są częścią Scali od wersji 2.5.
Wcześniej Scala, tak jak dotychczas Java, nie pozwalała na użycie konstruktora typu („generics” w Javie) jako parametru typu dla konstruktora typu. na przykład
nie było możliwe.
(Zdjęcie pochodzi z Generics of a Higher Kind )
Konsekwencją jest to, że ten konstruktor typów (np.
List
) Może być używany tak samo, jak inne typy w pozycji parametrów typu konstruktorów typów, a więc stały się typami pierwszej klasy od Scali 2.5. (Podobne do funkcji, które są wartościami pierwszej klasy w Scali).W kontekście systemu typów obsługującego wyższe rodzaje, możemy odróżnić odpowiednie typy , typy podobne
Int
lubList[Int]
od typów pierwszego rzędu, takie jakList
i typy wyższych rodzajów, takie jakFunctor
lubMonad
(typy, które wyodrębniają się nad typami, które wyodrębniają ponad typy).System typów Java po drugiej stronie nie obsługuje rodzajów, a zatem nie ma typów „wyższego rodzaju”.
Tak więc należy to rozpatrywać na tle systemu typów pomocniczych.
W przypadku Scali często widzisz przykłady takiego konstruktora typów
z nagłówkiem „Wyższe typy”, np. w Scali dla programistów ogólnych, sekcja 4.3
To jest czasami missleading, ponieważ odnoszą się do wielu
Container
jako wyższego typu kinded i nieIterable
, ale to, co jest bardziej precyzyjne jestźródło
Rodzaj zwykłych typów, jak
Int
iChar
, których przypadki są wartościami, jest*
. Konstruktorzy typu jednoargumentowego jakMaybe
to* -> *
; konstruktory typu binarnego, takie jakEither
( curry )* -> * -> *
, i tak dalej. Możesz przeglądać typy takie jakMaybe
iEither
jako funkcje na poziomie typu: pobierają jeden lub więcej typów i zwracają typ.Funkcja jest wyższego rzędu, jeśli ma rząd większy niż 1, gdzie porządek to (nieformalnie) głębokość zagnieżdżenia po lewej stronie strzałek funkcji:
1 :: Int
chr :: Int -> Char
fix :: (a -> a) -> a
,map :: (a -> b) -> [a] -> [b]
((A -> B) -> C) -> D
(((A -> B) -> C) -> D) -> E
Krótko mówiąc, wyższy rodzaj jest tylko funkcją wyższego rzędu na poziomie typu.
Int :: *
Maybe :: * -> *
Functor :: (* -> *) -> Constraint
—highher-kinded: konwertuje konstruktory typu jednoargumentowego na ograniczenia klasyźródło
Functor
tworzy odpowiedni typ (dobrze, cecha, ale ten sam pomysł)Functor[F[_]]
z konstruktora typówF
.(* => *) => (* => *)
można wyrazić w Scali? Jeśli nie, w innym języku?* ⇒ * ⇒ *
z curry jest bardzo pomocne. Dzięki!(* ⇒ *) ⇒ (* ⇒ *)
można również przeliterować(* ⇒ *) ⇒ * ⇒ *
. Można to wyrazić jak ScalaFoo[F[_], T]
. Jest to rodzaj typu (w Haskell)newtype Twice f a = Twice (f (f a))
(np.Twice Maybe Int
≅Maybe (Maybe Int)
,Twice [] Char
≅[[Char]]
) lub coś bardziej interesującego jak wolna monadadata Free f a = Pure a | Free (f (Free f a))
.Powiedziałbym: abstrakty typu wyższego rodzaju nad konstruktorem typów. Np. Rozważ
Oto
Functor
„wyższy rodzaj rodzaju” (tak jak w artykule „Generics of a Higher Kind” ). Nie jest to konstruktor typu konkretnego („pierwszego rzędu”)List
(który streszcza tylko odpowiednie typy). Abstrahuje od wszystkich konstruktorów typu jednoargumentowego („pierwszego rzędu”) (jak oznaczono za pomocąF[_]
).Innymi słowy: w Javie mamy wyraźne typy konstruktorów (np.
List<T>
), Ale nie mamy „typów o wyższych typach”, ponieważ nie możemy nad nimi streścić (np. Nie możemy napisaćFunctor
interfejsu zdefiniowanego powyżej - przynajmniej nie bezpośrednio ).Termin „polimorfizm wyższego rzędu (konstruktor typu)” jest używany do opisania systemów, które obsługują „typy wyższego rzędu”.
źródło
List<T>
w Javie byłby to konstruktor jednoargumentowy, ponieważ ma wyraźnie taki rodzaj* -> *
. W odpowiedzi Jona brakuje tego, że musisz umieć*
streścić „całość” (a nie tylko drugą, jak w Javie), aby nazwać ją typem wyższego rodzaju.def succ(x: Int) = x+1
wprowadza „konstruktor wartości” (zobacz moją drugą odpowiedź na to, co mam na myśli)succ
(nikt nie odniósłby się do tej wartości jako succ (x: Int)). Przez analogięFunctor
jest (rzeczywiście wyższy rodzaj) typ zdefiniowany w odpowiedzi. Znowu, nie należy odwoływać się do niego jakFunctor[F[_]]
(co jestF
to, co jest?_
Nie są one w zakres niestety, cukier syntaktyczny dla existentials muddies wody tutaj dokonując?!F[_]
SkrótF[T forSome {type T}]
)Scala REPL zapewnia
:kind
polecenie, któreNa przykład,
:help
Zapewnia jasne definicje więc myślę, że warto wpis go tutaj w całości (Scala 2.13.2)źródło