¿Qué es un tipo de tipo superior en Scala?
Puedes encontrar lo siguiente en la web:
Tipo de tipo superior == constructor de tipos?
class AClass[T]{...} // For example, class List[T]
Algunos dicen que este es un tipo de tipo superior, porque abstrae tipos que cumplirían con la definición.
Los tipos de tipo superior son tipos que toman otros tipos y construyen un nuevo tipo.
Sin embargo, estos también se conocen como constructores de tipos . (Por ejemplo, en Programación en Scala ).
¿Tipo de tipo superior == constructor de tipo que toma el constructor de tipo como parámetro de tipo?
En el artículo Genéricos de tipo superior , puedes leer
... tipos que se abstraen sobre tipos que se abstraen sobre tipos ('tipos de tipo superior') ..."
lo que sugiere que
class XClass[M[T]]{...} // or trait YTrait[N[_]]{...} // e.g. trait Functor[F[_]]
es un tipo de tipo superior.
Entonces, con esto en mente, es difícil distinguir entre constructor de tipos , tipo de tipo superior y constructor de tipos que toma constructores de tipos como parámetro de tipo , de ahí la pregunta anterior.
Permítanme compensar parte de esta confusión aportando algo de desambiguación. Me gusta usar la analogía con el nivel de valor para explicar esto, ya que la gente tiende a estar más familiarizada con él.
Un constructor de tipos es un tipo que puede aplicar a argumentos de tipo para "construir" un tipo.
Un constructor de valores es un valor que puede aplicar a argumentos de valor para "construir" un valor.
Los constructores de valores suelen denominarse "funciones" o "métodos". También se dice que estos "constructores" son "polimórficos" (porque pueden usarse para construir "cosas" de "forma variable") o "abstracciones" (ya que abstraen lo que varía entre diferentes instancias polimórficas).
En el contexto de la abstracción/polimorfismo, el primer orden se refiere al "uso único" de la abstracción: usted hace abstracción de un tipo una vez, pero ese tipo en sí no puede abstraer nada. Los genéricos de Java 5 son de primer orden.
La interpretación de primer orden de las caracterizaciones de abstracciones anteriores es:
Un constructor de tipos es un tipo que puede aplicar a argumentos de tipo adecuados para "construir" un tipo adecuado.
Un constructor de valores es un valor que puede aplicar a argumentos de valor adecuados para "construir" un valor adecuado.
Para enfatizar que no hay ninguna abstracción involucrada (supongo que se podría llamar a esto "orden cero", pero no he visto que se use en ninguna parte), como el valor 1
o el tipo String
, generalmente decimos que algo es un valor o tipo "adecuado".
Un valor adecuado es "utilizable inmediatamente" en el sentido de que no está esperando argumentos (no los abstrae). Piense en ellos como valores que puede imprimir/inspeccionar fácilmente (¡serializar una función es hacer trampa!).
Un tipo adecuado es un tipo que clasifica valores (incluidos los constructores de valores), los constructores de tipos no clasifican ningún valor (primero deben aplicarse a los argumentos de tipo correctos para generar un tipo adecuado). Para crear una instancia de un tipo, es necesario (pero no suficiente) que sea un tipo adecuado. (Puede ser una clase abstracta o una clase a la que no tienes acceso).
"Orden superior" es simplemente un término genérico que significa el uso repetido de polimorfismo/abstracción. Significa lo mismo para los tipos y valores polimórficos. Concretamente, una abstracción de orden superior abstrae sobre algo que abstrae sobre algo. Para los tipos, el término "de tipo superior" es una versión para fines especiales del más general "de orden superior".
Por tanto, la versión de orden superior de nuestra caracterización se convierte en:
Un constructor de tipos es un tipo que puede aplicar a argumentos de tipo (tipos adecuados o constructores de tipos) para "construir" un tipo adecuado (constructor).
Un constructor de valores es un valor que puede aplicar a argumentos de valor (valores adecuados o constructores de valores) para "construir" un valor adecuado (constructor).
Por lo tanto, "orden superior" simplemente significa que cuando dices "abstraer sobre X", ¡lo dices en serio! Lo X
que es abstraído no pierde sus propios "derechos de abstracción": puede abstraer todo lo que quiera. (Por cierto, uso el verbo "abstracto" aquí para significar: omitir algo que no es esencial para la definición de un valor o tipo, de manera que pueda ser variado/proporcionado por el usuario de la abstracción como argumento. .)
A continuación se muestran algunos ejemplos (inspirados en las preguntas de Lutz por correo electrónico) de valores y tipos adecuados, de primer orden y de orden superior:
proper first-order higher-order
values 10 (x: Int) => x (f: (Int => Int)) => f(10)
types (classes) String List Functor
types String ({type λ[x] = x})#λ ({type λ[F[x]] = F[String]})#λ
Donde las clases utilizadas se definieron como:
class String
class List[T]
class Functor[F[_]]
Para evitar la indirección mediante la definición de clases, necesita expresar de alguna manera funciones de tipo anónimo, que no se pueden expresar directamente en Scala, pero puede usar tipos estructurales sin demasiada sobrecarga sintáctica (el #λ
estilo se debe a https://stackoverflow.com /users/160378/retronym afaik):
En alguna hipotética versión futura de Scala que admita funciones de tipo anónimo, podría acortar la última línea de los ejemplos a:
types (informally) String [x] => x [F[x]] => F[String]) // I repeat, this is not valid Scala, and might never be
(En una nota personal, lamento haber hablado alguna vez de "tipos de tipo superior", ¡después de todo son solo tipos! Cuando sea absolutamente necesario eliminar la ambigüedad, sugiero decir cosas como "parámetro de constructor de tipo", "miembro de constructor de tipo" , o "alias de constructor de tipos", para enfatizar que no estamos hablando solo de tipos adecuados).
PD: Para complicar aún más las cosas, "polimórfico" es ambiguo de una manera diferente, ya que un tipo polimórfico a veces significa un tipo universalmente cuantificado, como Forall T, T => T
, que es un tipo adecuado, ya que clasifica valores polimórficos (en Scala, este valor puede ser escrito como el tipo estructural {def apply[T](x: T): T = x}
)
(Esta respuesta es un intento de decorar la respuesta de Adriaan Moors con información gráfica e histórica).
Los tipos de tipo superior son parte de Scala desde 2.5.
Antes de eso, Scala, como Java hasta ahora, no permitía usar un constructor de tipos ("genéricos" en Java) como parámetro de tipo para un constructor de tipos. p.ej
trait Monad [M[_]]
no fue posible.
En Scala 2.5, el sistema de tipos se había ampliado con la capacidad de clasificar tipos en un nivel superior (conocido como polimorfismo de constructor de tipos ). Estas clasificaciones se conocen como clases.
(Imagen derivada de Genéricos de tipo superior )
La consecuencia es que el constructor de tipos (por ejemplo
List
, ) podría usarse igual que otros tipos en la posición de los parámetros de tipo de los constructores de tipos y, por lo tanto, se convirtieron en tipos de primera clase desde Scala 2.5. (Similar a funciones que son valores de primera clase en Scala).En el contexto de un sistema de tipos que admite tipos superiores, podemos distinguir tipos propios , tipos como
Int
oList[Int]
de tipos de primer orden comoList
y tipos de tipo superior comoFunctor
oMonad
(tipos que se abstraen sobre tipos que se abstraen sobre tipos).Por otro lado, el sistema de tipos de Java no admite tipos y, por lo tanto, no tiene tipos de "tipo superior".
Así que esto debe verse en el contexto del sistema de tipos de apoyo.
En el caso de Scala, a menudo se ven ejemplos de un constructor de tipos como
trait Iterable[A, Container[_]]
con el título "Tipos de tipo superior", por ejemplo, en Scala para programadores genéricos, sección 4.3
Esto a veces es engañoso, porque muchos se refieren a
Container
tipo de tipo superior y noIterable
, pero lo que es más preciso es:el uso de
Container
como parámetro constructor de tipo de un tipo de tipo superior (orden superior) aquíIterable
.
El tipo de tipos ordinarios como Int
y Char
, cuyas instancias son valores, es *
. El tipo de constructores de tipo unario que les gusta Maybe
es * -> *
; constructores de tipo binario como Either
have ( curry ) kind * -> * -> *
, etc. Puede ver tipos como Maybe
y Either
como funciones de nivel de tipo: toman uno o más tipos y devuelven un tipo.
Una función es de orden superior si tiene un orden mayor que 1, donde el orden es (informalmente) la profundidad de anidamiento, a la izquierda, de las flechas de función:
- Orden 0:
1 :: Int
- Orden 1:
chr :: Int -> Char
- Orden 2:
fix :: (a -> a) -> a
,map :: (a -> b) -> [a] -> [b]
- Orden 3:
((A -> B) -> C) -> D
- Orden 4:
(((A -> B) -> C) -> D) -> E
Entonces, para resumir, un tipo de tipo superior es solo una función de orden superior a nivel de tipo que abstrae los constructores de tipos:
- Orden 0:
Int :: *
- Orden 1:
Maybe :: * -> *
- Orden 2:
Functor :: (* -> *) -> Constraint
—de tipo superior: convierte constructores de tipo unario en restricciones de clase de tipo
Yo diría: un tipo de tipo superior se abstrae sobre un constructor de tipos. Por ejemplo, considere
trait Functor [F[_]] {
def map[A,B] (fn: A=>B)(fa: F[A]): F[B]
}
Aquí Functor
hay un "tipo de tipo superior" (como se usa en el artículo "Genéricos de un tipo superior" ). No es un constructor de tipo concreto ("de primer orden") List
(que abstrae solo los tipos adecuados). Resume todos los constructores de tipo unario ("de primer orden") (como se indica con F[_]
).
O para decirlo de otra manera: en Java, tenemos claramente constructores de tipos (por ejemplo List<T>
), pero no tenemos "tipos de tipo superior", porque no podemos abstraerlos (por ejemplo, no podemos escribir la Functor
interfaz definida anteriormente). al menos no directamente ).
El término "polimorfismo de orden superior (constructor de tipos)" se utiliza para describir sistemas que admiten "tipos de tipo superior".