Narzędzie lub metoda rozpoznawania parametrów typu ogólnego Haskell [duplikat]
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ę id
i traverse
razem 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 ( id
i 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
, t
są przypisane do konkretnych typów.
Chcę automatycznie złapać i pokazać to mapowanie.
Odpowiedzi
Myślę, że f
i t
są bardziej ogólne Typ konstruktor parametry , jak działają one na rodzaj dać typ (ich rodzaj jest * -> *
, gdzie *
oznacza „rodzaj betonu”).
traverse id
Nie jest kompozycja, to funkcja aplikacji, ponieważ są przechodzącą id
jako argumentu do traverse
. this . that
jest kompozycją funkcji pomiędzy this
i that
, w sensie matematycznym, gdzie tworzysz funkcję, która podaje swój (pierwszy) argument jako dane wejściowe that
i 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 ord
to jest [Char] -> [Int]
, co możesz sprawdzić samodzielnie, pisząc :t map ord
w wierszu poleceń.
Jeśli podczas wpisywania spodziewasz się podobnego wyniku z typami konstruowanymi:t traverse id
, nie otrzymasz tego z prostego powodu, że traverse id
nadal 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 b
czego traverse
oczekuje, 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 traverse
w programie traverse (:[])
została utworzona instancja za pomocą f === []
i a === b
.