Ого, это старый!Я начну с небольшой очистки кода и приведения его в соответствие с текущими идиоматическими соглашениями:
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
Затем, без лишних слов, разбиваем код.Во-первых, у нас есть класс Flat
:
case class Flat[T, U](fn: T => List[U])
Это не что иное, как именованная оболочка для функции T => List[U]
, которая будет создавать List[U]
при задании экземпляра типа T
.Обратите внимание, что T
здесь также может быть List[U]
, или U
, или List[List[List[U]]]
и т. Д. Обычно такая функция может быть непосредственно указана в качестве типа параметра.Но мы собираемся использовать его косвенно, поэтому именованная оболочка позволяет избежать любого риска неявного конфликта.
Затем, работая в обратном направлении от recFlatten
:
def recFlatten[T, U](xs: List[T])(implicit f: Flat[List[T], U]) = f fn xs
ThisМетод возьмет xs
(List[T]
) и преобразует его в U
.Чтобы достичь этого, он находит неявный экземпляр Flat[T,U]
и вызывает вложенную функцию fn
Затем настоящая магия:
implicit def recFlattenFn[T, U](
implicit f: Flat[T, U] = Flat((xs: T) => List(xs))
) = Flat((xs: List[T]) => xs flatMap f.fn)
Это удовлетворяет неявному параметру, требуемому дляrecFlatten
, также требуется другой неявный параметр.Наиболее важно:
recFlattenFn
может выступать в качестве своего собственного неявного параметра - , он возвращает Flat [Список [X], X], поэтому
recFlattenFn
будет разрешено только неявнокак Flat[T,U]
, если T
- это List
- , то неявное
f
может вернуться к значению по умолчанию, если неявное разрешение не удается (т. е. T
НЕ является List
)
Возможно, это лучше всего понять в контексте одного из примеров:
recFlatten(List(List(1, 2, 3), List(4, 5)))
- Тип
T
выводится как List[List[Int]]
- неявныйпопытка поиска выполняется для `Flat [List [List [Int]], U]
- , которому соответствует рекурсивно определенный
recFlattenFn
В широком смысле:
recFlattenFn[List[List[Int]], U] ( f =
recFlattenFn[List[Int], U] ( f =
Flat[Int,U]((xs: T) => List(xs)) //default value
)
)
Обратите внимание, что recFlattenFn
будет соответствовать неявному поиску только для Flat[List[X], X]
, а параметры типа [Int,_]
не будут соответствовать этому совпадению, поскольку Int
не является List
.Это то, что вызывает откат к значению по умолчанию.
Вывод типа также работает в обратном направлении по этой структуре, разрешая параметр U
на каждом уровне рекурсии:
recFlattenFn[List[List[Int]], Int] ( f =
recFlattenFn[List[Int], Int] ( f =
Flat[Int,Int]((xs: T) => List(xs)) //default value
)
)
Это просто вложенность Flat
экземпляров, каждый из которых (кроме самого внутреннего) выполняет операцию flatMap
, чтобы развернуть один уровень вложенной структуры List
.Внутренний Flat
просто оборачивает все отдельные элементы в один List
.
QED