Ferramenta ou método de resolução de parâmetros de tipo genérico Haskell [duplicado]
Vejamos os tipos dessas funções, por exemplo:
:t traverse
traverse
:: (Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b)
:t id
id :: a -> a
Eles não têm tipos de concreto, mas têm parâmetros de tipo genérico : a
, f
, b
, t
(me corrija se chamavam não parâmetros de tipo genérico , por favor)
Se eu combinar id
e traverse
juntar desta forma,
:t traverse id [Just 1, Just 2, Nothing]
traverse id [Just 1, Just 2, Nothing] :: Num b => Maybe [b]
Haskell podem agora ligar-se alguns tipos de concreto para as variáveis tipo a
, f
, b
, t
.
t = []
a = Maybe bb
f = Maybe
b = Num bb => bb
Abaixo eu deduzo os tipos e mapeamentos para parâmetros manualmente, há alguma maneira ou ferramenta em Haskell para fazer isso automaticamente, de modo que pegue algumas partes compostas ( id
e traverse
) em um exemplo, extraia suas assinaturas de tipo em geral e na saída produz um mapeamento de nomes de parâmetros de tipo genérico para tipos inferidos concretos?
Veja também o primeiro exemplo aqui: https://wiki.haskell.org/Type_inferencepara a expressão " map ord
" em como Haskell encontra ligações de tipos reais para nomes.
Assim, quando olhamos para funções separadamente só temos nomes a
, f
, b
, t
. Mas, então, combinar as funções e fornecer algumas informações extra como [Just 1, Just 2, Nothing]
, e os nomes a
, f
, b
, t
são mapeados para tipos de concreto.
Quero capturar e mostrar esse mapeamento automaticamente.
Respostas
Eu penso f
e t
são mais genéricas tipo construtor parâmetros , como eles agem em um tipo para lhe dar um tipo (que tipo é * -> *
, em que *
os meios "um tipo concreto").
traverse id
Não é a composição, é a aplicação de função, como você está passando id
como um argumento para traverse
. this . that
é a composição da função entre this
e that
, no sentido matemático, onde você cria uma função que fornece seu (primeiro) argumento como uma entrada para that
e alimenta o resultado desta aplicação para this
.
Você se refere ao exemplo nesta página, onde dado este
map :: (a -> b) -> [a] -> [b]
Char.ord :: (Char -> Int)
o compilador é capaz de deduzir que o tipo de map ord
é [Char] -> [Int]
, como você mesmo pode verificar escrevendo :t map ord
na linha de comando.
Se você espera uma saída semelhante com tipos conceretos ao digitar :t traverse id
, não a obterá, pelo simples motivo de que traverse id
ainda é uma função polimórfica, tanto em seus argumentos de tipo concreto quanto em argumentos de construtor de tipo.
Apenas para dar um exemplo um pouco diferente, se você digitar :t traverse (:[])
, onde (:[])
tem tipo a -> [a]
, que é um caso particular do (Applicative f) => a -> f b
que traverse
espera, você obterá esta saída,
traverse (:[]) :: Traversable t => t b -> [t b]
que, comparado com :t traverse
,
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
informa que traverse
, em traverse (:[])
, foi "instanciado" com f === []
e a === b
.