Esta questão não é subjetiva. Um verbo muito específico é usado no livro referenciado, e eu gostaria de entender qual é a implicação dessa frase, porque temo estar entendendo mal alguma coisa.
De Learn You a Haskell , o parágrafo a seguir é o terceiro e o último que contém "assumimos *
".
data Barry t k p = Barry { yabba :: p, dabba :: t k }
E agora queremos fazer disso uma instância do
Functor
.Functor
quer tipos do tipo,* -> *
masBarry
não parece ter esse tipo. Qual é o tipo deBarry
? Bem, vemos que são necessários três parâmetros de tipo, então serásomething -> something -> something -> *
. É seguro dizer quep
é um tipo concreto e, portanto, tem um tipo de*
. Poisk
, assumimos*
e, por extensão,t
tem uma espécie de* -> *
. Agora, vamos substituir esses tipos pelossomething
s que usamos como espaços reservados e vemos que tem um tipo de(* -> *) -> * -> * -> *
.
Por que estamos assumindo alguma coisa? Ao ler "assumimos X (ou seja, assumimos que X é verdadeiro)", é natural para mim pensar que também devemos considerar o caso de que X é falso. No caso específico do exemplo, não poderia t
ser do tipo (* -> *) -> *
e k
do tipo (* -> *)
? Se fosse esse o caso, qualquer que fosse t
e k
realmente fosse, t k
ainda seria um tipo concreto, não?
Vejo que toda a linha de raciocínio é então verificada no compilador, mas não acho que o compilador assuma . Se isso acontecer, gostaria de saber o que, se não acontecer, novamente. Receio estar perdendo o significado do parágrafo.
k :: L
para qualquer tipoL
, desde quet :: L -> *
. Um compilador aqui deve, no entanto, escolher alguns específicosL
ou recorrer a uma polignidade. Uma poli-classe seria a opção mais geral, mas aqui o GHC escolheL = *
(Haskell básico não tem poli-classes, elas precisam ser ativadas como uma extensão). Como escolhe algo arbitrário, a LYAH usa a palavra "assumir" (AFAICT).Respostas:
De fato, o compilador assume! Mas você pode pedir que não o faça com a extensão PolyKinds. Você pode ler sobre isso com mais detalhes aqui . Com essa extensão ativada, o tipo de
Barry
seráforall k. (k -> *) -> k -> * -> *
.fonte
Bom ponto. O autor faz uma suposição desnecessária. Talvez apenas para facilitar a compreensão em seu capítulo Type Foo, mas pessoas como você podem legitimamente questionar isso.
Ambos
t
,k
ep
são variáveis de tipo. Como podemos ver,yabba :: p
ele pode viver sozinho, então é como uma função constante, como se fosse um valor em vez de um tipo, sua assinatura de tipo diriaInt
ouChar
, seja o que for ... o nome dele. Mas como é um tipo, é uma assinatura gentil*
.No entanto,
t
type aqui utiliza uma variável de tipok
para construir um type (dabba :: t k
),portanto, temos certeza de que (sem suposição aqui).t
possui uma assinatura de tipo como* -> *
ek
possui*
Uma vez que sabemos que isso ... o tipo
Barry t k p
de assinatura tipo é(* -> *) -> * -> * -> *
o que significa que é precisot
, em seguida,k
e, em seguida,p
e dar-nosBarry
escrever.Editar Certifique-se de ler o comentário de @ luqui abaixo.
fonte
k
não é restrito a ser*
como você afirma que é ao deduzirt
. Poderíamos terk :: * -> *
et :: (* -> *) -> *
, por exemplo. Adicione um campodoo :: k Int
ao registro e ele passará sem problemas.