¡Oh, guau, esta es una vieja! Voy a empezar por la limpieza del código un poco y tirando de él en línea con las convenciones idiomáticas actuales:
case class Flat[T, U](fn: T => List[U])
implicit def recFlattenFn[T, U](
implicit f: Flat[T, U] = Flat((xs: T) => List(xs))
) = Flat((xs: List[T]) => xs flatMap f.fn)
def recFlatten[T, U](xs: List[T3])(implicit f: Flat[List[T], U]) = f fn xs
Entonces, sin más preámbulos, descomponen el código.En primer lugar, tenemos nuestra clase Flat
:
case class Flat[T, U](fn: T => List[U])
Esto no es nada más que un envoltorio lleva el nombre de la función T => List[U]
, una función que va a construir una List[U]
cuando se les da una instancia de tipo T
. Tenga en cuenta que T
aquí también podría ser un List[U]
, o un U
, o un List[List[List[U]]]
, etc. Normalmente, dicha función se podría especificar directamente como el tipo de un parámetro. Pero vamos a usar este en implicits, por lo que el contenedor con nombre evita cualquier riesgo de un conflicto implícito.
Entonces, trabajando hacia atrás desde recFlatten
:
def recFlatten[T, U](xs: List[T])(implicit f: Flat[List[T], U]) = f fn xs
Este método se llevará a xs
(un List[T]
) y convertirlo en un U
. Para lograr esto, se localiza una instancia implícita de Flat[T,U]
e invoca la función cerrada, fn
Entonces, la verdadera magia:
implicit def recFlattenFn[T, U](
implicit f: Flat[T, U] = Flat((xs: T) => List(xs))
) = Flat((xs: List[T]) => xs flatMap f.fn)
Esto satisface el parámetro implícito requerido por recFlatten
, sino que también da un parámetro de implícita . Lo más crucial:
recFlattenFn
puede actuar como su propio parámetro implícito
- devuelve un plano [Lista [X], X], por lo
recFlattenFn
sólo se pueden resolver de forma implícita como Flat[T,U]
si T
es una List
- lo implícito
f
se repliegue a un valor por defecto si falla la resolución implícita (es decir, no es un T
List
)
Perha ps esta se entiende mejor en el contexto de uno de los ejemplos:
recFlatten(List(List(1, 2, 3), List(4, 5)))
- El tipo
T
se infiere como List[List[Int]]
- de búsqueda implícita se intenta para un `Flat [Lista [Lista [Int]], U]
- este se corresponde con una forma recursiva define
recFlattenFn
términos generales:
recFlattenFn[List[List[Int]], U] (f =
recFlattenFn[List[Int], U] (f =
Flat[Int,U]((xs: T) => List(xs)) //default value
)
)
Tenga en cuenta que recFlattenFn
sólo igualará una búsqueda implícita para una Flat[List[X], X]
y el tipo params [Int,_]
fallan este partido porque Int
no es un List
. Esto es lo que desencadena el retorno al valor predeterminado.
La inferencia de tipos también trabaja hacia atrás hasta que la estructura, la resolución del parámetro U
en cada nivel de recursividad:
recFlattenFn[List[List[Int]], Int] (f =
recFlattenFn[List[Int], Int] (f =
Flat[Int,Int]((xs: T) => List(xs)) //default value
)
)
que es sólo un anidamiento de Flat
casos, cada uno de ellos (excepto el más interno) realizar una flatMap
operación para desenrollar un nivel de la estructura anidada List
. El Flat
más interno simplemente envuelve todos los elementos individuales en una sola copia List
.
Q.E.D.
Gracias eso ayuda mucho. Creo que en su ejemplo los parámetros de tipo están desactivados por un ajuste. Esto compila 'recFlatten [Lista [Int], Int] (Lista (Lista (1, 2, 3), Lista (4, 5))) ( recFlattenFn [Lista [Int], Int] (f = recFlattenFn [Int , Int] (F = Villa [Int, Int] ((xs: int) => Lista (xs)) // valor predeterminado ) ) ) ' – huynhjl
Muy bien, ahora actualizado :) –