Você pode encontrar o seguinte na web:
Tipo de classificação superior == tipo de construtor?
class AClass[T]{...} // For example, class List[T]
Alguns dizem que esse é um tipo de classificação mais alta, porque abstrai sobre tipos que seriam compatíveis com a definição.
Tipos de classificação superior são aqueles que usam outros tipos e constroem um novo tipo
Estes também são conhecidos como construtor de tipos . (Por exemplo, em Programação no Scala ).
Tipo de classificação superior == construtor de tipos que usa o construtor de tipos como um parâmetro de tipo?
No artigo Genéricos de tipo superior , você pode ler
... tipos que abstraem sobre tipos que abstraem sobre tipos ('tipos superiores') ... "
o que sugere que
class XClass[M[T]]{...} // or trait YTrait[N[_]]{...} // e.g. trait Functor[F[_]]
é um tipo de classificação superior.
Portanto, com isso em mente, é difícil distinguir entre construtor de tipo , tipo superior e construtor de tipo que toma construtores de tipo como parâmetro de tipo , portanto, a pergunta acima.
Respostas:
Deixe-me compensar o começo de uma confusão confusa com alguma desambiguação. Eu gosto de usar a analogia com o nível de valor para explicar isso, pois as pessoas tendem a estar mais familiarizadas com ela.
Construtores de valor são geralmente chamados de "funções" ou "métodos". Também se diz que esses "construtores" são "polimórficos" (porque podem ser usados para construir "coisas" de "forma" variável) ou "abstrações" (uma vez que abstraem o que varia entre instanciações polimórficas diferentes).
No contexto de abstração / polimorfismo, primeira ordem se refere ao "uso único" da abstração: você abstrai um tipo uma vez, mas esse tipo em si não pode abstrair nada. Os genéricos Java 5 são de primeira ordem.
A interpretação de primeira ordem das caracterizações acima de abstrações é:
Para enfatizar, não há abstração envolvida (acho que você poderia chamar isso de "ordem zero", mas eu nunca vi isso usado em nenhum lugar), como o valor
1
ou o tipoString
, geralmente dizemos que algo é um valor ou tipo "adequado".Um valor adequado é "imediatamente utilizável" no sentido de que não está aguardando argumentos (não é abstraído sobre eles). Pense neles como valores que você pode imprimir / inspecionar facilmente (serializar uma função é trapaça!).
Um tipo adequado é um tipo que classifica valores (incluindo construtores de valor); os construtores de tipo não classificam nenhum valor (eles primeiro precisam ser aplicados aos argumentos de tipo corretos para produzir um tipo adequado). Para instanciar um tipo, é necessário (mas não suficiente) que seja um tipo adequado. (Pode ser uma classe abstrata ou uma classe à qual você não tem acesso.)
"Ordem superior" é simplesmente um termo genérico que significa uso repetido de polimorfismo / abstração. Significa o mesmo para tipos e valores polimórficos. Concretamente, uma abstração de ordem superior abstrai sobre algo que abstrai sobre algo. Para tipos, o termo "tipo superior" é uma versão para fins especiais da "ordem superior" mais geral.
Assim, a versão superior de nossa caracterização se torna:
Assim, "ordem superior" significa simplesmente que, quando você diz "abstraindo sobre X", realmente entende! O
X
que é abstraído não perde seus próprios "direitos de abstração": pode abstrair tudo o que deseja. (A propósito, eu uso o verbo "abstract" aqui para significar: deixar de fora algo que não é essencial para a definição de um valor ou tipo, para que possa ser variado / fornecido pelo usuário da abstração como argumento .)Aqui estão alguns exemplos (inspirados nas perguntas de Lutz por email) de valores e tipos adequados, de primeira e de mais alta ordem:
Onde as classes usadas foram definidas como:
Para evitar a indireção através da definição de classes, é necessário expressar de alguma forma funções de tipo anônimo, que não são expressáveis diretamente no Scala, mas você pode usar tipos estruturais sem muita sobrecarga sintática (o
#λ
estilo é devido a https://stackoverflow.com / users / 160378 / retronym afaik):Em alguma versão futura hipotética do Scala que suporta funções do tipo anônimo, você pode encurtar a última linha dos exemplos para:
(Em uma nota pessoal, lamento já ter falado sobre "tipos de classe superior", eles são apenas tipos afinal! Quando você absolutamente precisar desambiguar, sugiro dizer coisas como "parâmetro do construtor de tipo", "membro do construtor de tipo" , ou "alias do construtor de tipos", para enfatizar que você não está falando apenas de tipos adequados.)
ps: Para complicar ainda mais, "polimórfico" é ambíguo de uma maneira diferente, pois um tipo polimórfico às vezes significa um tipo quantificado universalmente, como
Forall T, T => T
, que é um tipo adequado, pois classifica valores polimórficos (em Scala, esse valor pode ser escrito como o tipo estrutural{def apply[T](x: T): T = x}
)fonte
(Esta resposta é uma tentativa de decorar a resposta de Adriaan Moors com algumas informações gráficas e históricas.)
Tipos superiores são parte do Scala desde 2.5.
Antes disso, o Scala, como Java até agora, não permitia usar o construtor de tipo ("genéricos" em Java) para ser usado como parâmetro de tipo para um construtor de tipo. por exemplo
não foi possível.
(Imagem derivada de genéricos de tipo superior )
A conseqüência é que esse tipo de construtor (por exemplo
List
) poderia ser usado como outros tipos na posição de parâmetro de tipo de construtores de tipo e, portanto, eles se tornaram tipos de primeira classe desde o Scala 2.5. (Semelhante às funções que são valores de primeira classe no Scala).No contexto de um sistema de tipos que suporta tipos mais altos, podemos distinguir tipos adequados , tipos como
Int
ouList[Int]
de tipos de primeira ordem comoList
e tipos de tipos mais altos comoFunctor
orMonad
(tipos que abstraem sobre tipos que abstraem sobre tipos).O sistema de tipos de Java, por outro lado, não suporta tipos e, portanto, não possui tipos de "tipo superior".
Portanto, isso deve ser visto no contexto do sistema de tipos de suporte.
No caso do Scala, você costuma ver exemplos de um construtor de tipos como
com o título "Tipos superiores", por exemplo, em Scala para programadores genéricos, seção 4.3
Isso às vezes é missleading, porque muitos se referem
Container
como tipo superior kinded e nãoIterable
, mas o que é é mais preciso,fonte
O tipo de tipos comuns como
Int
eChar
, cujas instâncias são valores, é*
. O tipo de construtores de tipo unário comoMaybe
é* -> *
; construtores de tipo binário, comoEither
have ( curried )* -> * -> *
, e assim por diante. Você pode visualizar tipos comoMaybe
eEither
como funções no nível de tipo: eles pegam um ou mais tipos e retornam um tipo.Uma função é de ordem superior se tiver uma ordem maior que 1, onde a ordem é (informalmente) a profundidade de aninhamento, à esquerda, das setas de função:
1 :: Int
chr :: Int -> Char
fix :: (a -> a) -> a
,map :: (a -> b) -> [a] -> [b]
((A -> B) -> C) -> D
(((A -> B) -> C) -> D) -> E
Portanto, para encurtar a história, um tipo de tipo superior é apenas uma função de ordem superior no nível de tipo.
Int :: *
Maybe :: * -> *
Functor :: (* -> *) -> Constraint
- de tipo mais alto: converte construtores de tipo unário em restrições de classe de tipofonte
Functor
produz um tipo adequado (bem, característica, mas mesma ideia)Functor[F[_]]
de um construtor de tiposF
.(* => *) => (* => *)
ser expresso em Scala? Se não, em outro idioma?* ⇒ * ⇒ *
com o curry é muito útil. Obrigado!(* ⇒ *) ⇒ (* ⇒ *)
também pode ser escrito(* ⇒ *) ⇒ * ⇒ *
. Pode ser expresso em Scala comoFoo[F[_], T]
. É o tipo de tipo como (em Haskell)newtype Twice f a = Twice (f (f a))
(por exemplo,Twice Maybe Int
≅Maybe (Maybe Int)
,Twice [] Char
≅[[Char]]
) ou algo mais interessante como a mônada livredata Free f a = Pure a | Free (f (Free f a))
.Eu diria: Um tipo de tipo mais alto abstrai um construtor de tipo. Por exemplo, considere
Aqui
Functor
está um "tipo superior" (conforme usado no artigo "Genéricos de um tipo superior" ). Não é um construtor de tipo concreto ("de primeira ordem")List
(que abstrai apenas tipos adequados). Ele abstrai todos os construtores do tipo unário ("de primeira ordem") (como indicado emF[_]
).Ou, de outra forma: em Java, temos claramente tipos de construtores (por exemplo
List<T>
), mas não temos "tipos de classificação superior", porque não podemos abstrair sobre eles (por exemplo, não podemos escrever aFunctor
interface definida acima - pelo menos não diretamente ).O termo "polimorfismo de ordem superior (construtor de tipos)" é usado para descrever sistemas que suportam "tipos de classificação superior".
fonte
List<T>
em Java, seria um construtor de tipo unário, pois tem claramente esse tipo* -> *
. O que está faltando na resposta de Jon é que você deve ser capaz de abstrair a "coisa toda" (e não apenas a segunda*
como em Java) para chamá-la de um tipo de classificação superior.def succ(x: Int) = x+1
introduz o "construtor de valor" (veja minha outra resposta para o que quero dizer com isso)succ
(ninguém se referiria a esse valor como succ (x: Int)). Por analogia,Functor
é o tipo (de fato de tipo mais alto) definido em sua resposta. Novamente, você não deve se referir a ele comoFunctor[F[_]]
(o que éF
? O que é_
? Eles não estão no escopo! Infelizmente, o açúcar sintático para os existenciais turva as águas aqui, abreviandoF[_]
paraF[T forSome {type T}]
)O Scala REPL fornece um
:kind
comando quePor exemplo,
Ele
:help
fornece definições claras, então acho que vale a pena publicá-la aqui na íntegra (Scala 2.13.2)fonte