Narzędzie lub metoda rozpoznawania parametrów typu ogólnego Haskell [duplikat]

Dec 12 2020

Przyjrzyjmy się na przykład typom tych funkcji:

:t traverse
traverse
  :: (Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b)

:t id
id :: a -> a

Nie mają żadnych konkretnych typów, ale mają parametry typu rodzajowego : a, f, b, t(poprawcie mnie jeśli nie nazwali parametry typu rodzajowego proszę)

Jeśli połączę idi traverserazem w ten sposób,

:t traverse id [Just 1, Just 2, Nothing] 
traverse id [Just 1, Just 2, Nothing] :: Num b => Maybe [b]

Haskell może teraz związać kilka rodzajów betonu dla zmiennych typu a, f, b, t.

t = []
a = Maybe bb
f = Maybe
b = Num bb => bb

Poniżej wnioskuję ręcznie o typach i mapowaniach do parametrów, czy w Haskell jest jakikolwiek sposób lub narzędzie, aby zrobić to automatycznie, tak aby wymagało to niektórych części składowych ( idi traverse) w przykładzie wyodrębnia ich sygnatury typów w ogóle, a na wyjściu mapowanie z nazw parametrów typu ogólnego na konkretne wywnioskowane typy?

Zobacz także pierwszy przykład tutaj: https://wiki.haskell.org/Type_inferencedla wyrażenia " map ord" o tym, jak Haskell znajduje powiązania rzeczywistych typów z nazwami.

Więc kiedy patrzymy na funkcji osobno mamy tylko nazwy a, f, b, t. Ale potem łączą funkcje i zapewniają dodatkowe informacje, jak [Just 1, Just 2, Nothing]i nazwiska a, f, b, tsą przypisane do konkretnych typów.

Chcę automatycznie złapać i pokazać to mapowanie.

Odpowiedzi

Enlico Dec 12 2020 at 00:55

Myślę, że fi tsą bardziej ogólne Typ konstruktor parametry , jak działają one na rodzaj dać typ (ich rodzaj jest * -> *, gdzie *oznacza „rodzaj betonu”).

traverse idNie jest kompozycja, to funkcja aplikacji, ponieważ są przechodzącą idjako argumentu do traverse. this . thatjest kompozycją funkcji pomiędzy thisi that, w sensie matematycznym, gdzie tworzysz funkcję, która podaje swój (pierwszy) argument jako dane wejściowe thati przekazuje wynik tej aplikacji do this.

Odsyłasz do przykładu na tej stronie, gdzie to podano

map :: (a -> b) -> [a] -> [b]
Char.ord :: (Char -> Int)

kompilator jest w stanie wywnioskować, że typ map ordto jest [Char] -> [Int], co możesz sprawdzić samodzielnie, pisząc :t map ordw wierszu poleceń.

Jeśli podczas wpisywania spodziewasz się podobnego wyniku z typami konstruowanymi:t traverse id , nie otrzymasz tego z prostego powodu, że traverse idnadal jest to funkcja polimorficzna, zarówno w argumentach typu konkretnego, jak i argumentach konstruktora typu.

Aby dać nieco inny przykład, jeśli wpiszesz :t traverse (:[]), gdzie (:[])ma typ a -> [a], co jest szczególnym przypadkiem tego, (Applicative f) => a -> f bczego traverseoczekuje, otrzymasz to wyjście,

traverse (:[]) :: Traversable t => t b -> [t b]

który w porównaniu z :t traverse,

traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)

informuje, że traversew programie traverse (:[])została utworzona instancja za pomocą f === []i a === b.