Rutas
/
Julia
Julia
/
Ejercicios
/
Gurú de las calificaciones
Gurú de las calificaciones

Gurú de las calificaciones

Ejercicio de aprendizaje

Introducción

Hasta ahora, el temario no ha dicho mucho sobre los tipos, pero está claro que existen en Julia:

julia> vals = (42, 4.3, π, "hello", 'Q')
(42, 4.3, π, "hello", 'Q')
julia> typeof(vals)
Tuple{Int64, Float64, Irrational{:π}, String, Char}

Nunca especificamos los tipos, pero Julia los asignó de todos modos.

  1. Julia tiene types, que son fundamentales en su diseño.
  2. Julia normalmente puede «adivinar» el tipo, usando Type Inference.

El compilador JIT examinará (todo) el código, verá cómo se usa una variable e inferirá un tipo por defecto adecuado y compatible con ese uso.

Asignación de tipos

Confiar en la inferencia de tipos está bien para resolver ejercicios sencillos de tutorial, pero en programas más grandes es probable que necesites un control más preciso.

En la mayoría de los procesadores modernos, un número entero tiene Int64 por defecto. Vimos en el concepto Numbers que se puede convertir un valor a un tipo concreto distinto del predeterminado.

julia> x = Int16(42)
42
julia> typeof(x)
Int16

Sin embargo, la variable x todavía se puede reasignar a un tipo diferente:

julia> x = "changed"
"changed"
julia> typeof(x)
String

Esto es type instability, que es:

  • Muy cómoda en scripts pequeños.
  • Mala para el rendimiento y la fiabilidad en programas más grandes.

En su lugar, podemos establecer el tipo de x usando el operador :::

julia> y::Int16 = 42
42
julia> typeof(y)
Int16
julia> y = "changed"
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Int16
The function `convert` exists, but no method is defined for this combination of argument types.

Ahora y es, y siempre será, de tipo Int16. Así, el compilador sabe cuántos bytes reservar para ella y puede optimizar el resto del código para apoyarse en un tipo estable. En esto, la variable es más o menos similar a las de un lenguaje de tipado estático como C.

La jerarquía de tipos

Int64, Int16, String, Char: ¿de dónde «vienen» estos tipos?

En muchos lenguajes orientados a objetos (OO), cada tipo es una clase, la creación de subclases las organiza en una jerarquía de clases y los métodos de clase definen los comportamientos.

Java y Ruby son ejemplos evidentes de este patrón, pero incluso Python es similar internamente.

Julia no tiene clases.

La razón documentada es que las características de la programación orientada a objetos interfieren con el compilador JIT y perjudican el rendimiento en tiempo de ejecución.

Y, sin embargo, mira este código:

julia> y::Int16 = 42
42
julia> typeof(y)
Int16
julia> supertype(Int16)
Signed
julia> supertypes(Int16)
(Int16, Signed, Integer, Real, Number, Any)

Con algunos detalles más:

  • Int16 es un tipo, y podemos crear variables de este tipo.
  • Int16 es un subtipo de Signed, y la función supertype() nos lo muestra.
  • Hay una jerarquía de tipos que asciende por Integer, Real y Number hasta Any en la cima, y subtypes() nos listará esta rama de la jerarquía.

Todas las ramas terminan en Any, que tiene la particularidad de ser su propio supertipo.

julia> supertypes(String)
(String, AbstractString, Any)
julia> supertype(Any)
Any

Así que Julia no tiene una jerarquía de class, pero sí tiene una jerarquía de type.

Con el tiempo, intentaremos desentrañar cómo funciona esto, pero antes hay mucho más que explorar.

Comprobar tipos

Podemos usar typeof() para comprobar la igualdad de la forma habitual.

julia> typeof(11)
Int64
julia> typeof(11) == Int64
true
julia> typeof(11) == Number
false

La igualdad de tipos debe ser exacta, ya que esta forma de comparación no entiende de jerarquías de tipos.

De forma más flexible, isa nos dirá si un valor tiene el mismo tipo que un comparador o un subtipo de este. Se puede usar tanto en forma de función como de infijo.

julia> 12 isa Int64
true
julia> 12 isa Number
true
julia> isa(12, Number)
true
julia> 12 isa String
false

Ten en cuenta que isa espera un value a la izquierda, no un type.

Intentar comparar dos tipos de esta forma dará resultados inesperados. El operador correcto es <:, que veremos mucho más en conceptos futuros.

julia> Int64 isa Number  ## Don't do this!
false
julia> Int64 <: Number
true

Tipos abstractos y concretos

Vimos que la jerarquía de tipos forma una estructura de árbol (en el sentido de las ciencias de la computación, con la raíz arriba).

Cada elemento del árbol es un node, y estos se pueden dividir en categorías:

  1. Los nodos con subtipos se llaman abstract.
  2. Los nodos hoja, sin subtipos, se llaman concrete.
julia> subtypes(Integer)  # an abstract type
3-element Vector{Any}:
 Bool
 Signed
 Unsigned
julia> subtypes(Int64)  # a concrete type
Type[]

Esta es una distinción importante, porque solo los tipos concretos se pueden instantiated como variables.

julia> a::Int16 = 42
42
julia> typeof(a)
Int16
julia> b::Integer = 42
42
julia> typeof(b)
Int64

Ten en cuenta que intentar usar un tipo abstracto no da ningún mensaje de error (en este caso), pero el compilador crea un tipo concreto adecuado: Int64 en lugar de Integer.

Instrucciones

En este ejercicio vas a hacer un poco de ingeniería de datos preprocesando algunos datos de calificaciones. Una escuela con muchos, muchos, muchos (¿demasiados?) estudiantes está intentando hacer un análisis de datos de las calificaciones que reciben los estudiantes y busca hacerlo de forma eficiente, así que la idea es minimizar y organizar los datos.

La escala de calificaciones suele ir de 0 a 10, así que lo más eficiente es usar un tipo de datos con solo ocho bits por calificación.

  • Algunos profesores usan números reales (porque son muy quisquillosos con la precisión), y tendrás que convertirlos al tipo de datos UInt8.
  • Otros profesores usan números enteros con números negativos (para castigar a los estudiantes especialmente revoltosos), y en estos casos tendrás que convertirlos al tipo de datos Int8.

Una vez que hayas implementado la función para convertir las calificaciones, tendrás que escribir otra para manejar las colecciones en las que se guardan, degradando las calificaciones y devolviéndolas en orden descendente.

  • Algunos profesores usan Vectors ordenados de forma ascendente para guardar sus calificaciones, porque son meticulosos con sus datos.
  • Otros profesores usan Sets, que no están ordenados, para guardar sus calificaciones, porque son un poco más perezosos.

En ambas funciones tendrás que manejar las entradas no válidas lanzando un MethodError.

Note

El manejo de excepciones se tratará en un Concepto posterior, así que, para los fines de este ejercicio, puedes usar la siguiente sintaxis:

throw(MethodError(f, args))

Donde f es la función y args es una tupla con los argumentos de entrada de la función. Con la función demote(n), f es demote y args es (n,):

throw(MethodError(demote, (n,)))

1. Degrada las calificaciones

Implementa el método demote(n).

  • Con una entrada Float64, debe redondear hacia arriba al número entero más cercano y devolver un tipo de datos UInt8.
  • Con un Integer arbitrario, debe devolver el mismo entero en un tipo de datos Int8.
  • Cualquier otra entrada debe lanzar un MethodError.
julia> demote(4.2)::UInt8
5

julia> demote(4)::Int8
4

julia> demote("hi")
MethodError: no method matching demote(::String)     #output truncated

2. Preprocesa los datos

Implementa el método preprocess(coll).

  • Con una entrada Vector, debe degradar todos los números e invertir el vector.
  • Con una entrada Set, debe degradar todos los números y devolver un vector ordenado en orden descendente.
  • Cualquier otra entrada debe lanzar un MethodError.
julia> preprocess([1, 2, 3])
3-element Vector{Int8}:
 3
 2
 1

julia> preprocess(Set([2.2, 5.8, 3.4]))
3-element Vector{UInt8}:
 6
 4
 3

julia> preprocess(42)
MethodError: no method matching preprocess(::Int64)     #output truncated
Editar en GitHub El enlace se abre en una ventana o pestaña nueva
Julia Exercism

¿Listo para empezar Gurú de las calificaciones?

Regístrate en Exercism para aprender y dominar Julia con 35 conceptos128 ejercicios y mentoría humana real, todo gratis.