Och, wow, to jest stare! Zacznę od czyszczenia kod trochę i pociągnięcie go do aktualnych konwencji idiomatyczne:
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
Następnie, bez dalszej zwłoki, załamać kod.Po pierwsze, mamy Flat
Klasa:
case class Flat[T, U](fn: T => List[U])
to nic więcej niż o nazwie wrapper dla funkcji T => List[U]
, to funkcja, która wybuduje List[U]
gdy dana instancja typu T
. Zauważ, że tutaj T
może być również List[U]
lub U
lub List[List[List[U]]]
itd. Zwykle taka funkcja może być bezpośrednio określona jako typ parametru. Ale zamierzamy używać tego w implikacjach, więc nazwany wrapper unika ryzyka niejawnego konfliktu.
Następnie działa wstecz od recFlatten
:
def recFlatten[T, U](xs: List[T])(implicit f: Flat[List[T], U]) = f fn xs
Metoda ta odbędzie xs
(a List[T]
) i przekształcić go w U
. Aby to osiągnąć, lokalizuje niejawny wystąpienie Flat[T,U]
i wywołuje funkcję zamknięty, fn
Następnie prawdziwą magię:
implicit def recFlattenFn[T, U](
implicit f: Flat[T, U] = Flat((xs: T) => List(xs))
) = Flat((xs: List[T]) => xs flatMap f.fn)
ten spełnia parametr niejawny wymaganych recFlatten
, ale również bierze udział niejawny paramater . Co najważniejsze:
recFlattenFn
może działać jako własnej niejawnym parametrem
- zwraca płaską [Lista [x] X], więc
recFlattenFn
zostaną niejawnie rozwiązany tylko jako Flat[T,U]
jeśli T
jest List
- niejawny
f
może awaryjne na wartość domyślną, jeśli nie powiedzie się niejawna rozdzielczości (tj T
NIE jest List
)
Perha ps ta jest najlepiej rozumiana w kontekście jednego z przykładów:
recFlatten(List(List(1, 2, 3), List(4, 5)))
- Typ
T
jest wywnioskować jak List[List[Int]]
- niejawna odnośnika próby dla `Flat [Lista [List [Int]] U]
- to jest dopasowane przez zdefiniowane rekurencyjnie
recFlattenFn
Ogólnie mówiąc:
recFlattenFn[List[List[Int]], U] (f =
recFlattenFn[List[Int], U] (f =
Flat[Int,U]((xs: T) => List(xs)) //default value
)
)
Zauważ, że recFlattenFn
będzie pasował tylko niejawnego poszukiwania Flat[List[X], X]
oraz rodzaj params [Int,_]
nie ten mecz, ponieważ Int
nie jest List
. To właśnie powoduje powrót do wartości domyślnej.
Rodzaj wnioskowanie działa również wstecz się tej struktury, rozwiązywaniu U
param na każdym poziomie rekurencji:
recFlattenFn[List[List[Int]], Int] (f =
recFlattenFn[List[Int], Int] (f =
Flat[Int,Int]((xs: T) => List(xs)) //default value
)
)
Który jest po prostu zagnieżdżanie Flat
przypadkach, każdy z nich (oprócz najgłębsza) przeprowadzenie flatMap
operacja, aby rozwinąć jeden poziom zagnieżdżonej struktury List
. Najbardziej wewnętrzna Flat
po prostu opakowuje wszystkie pojedyncze elementy z powrotem w pojedynczym List
.
Q.E.D.
Dziękuję, że bardzo pomaga. Myślę, że w twoim przykładzie parametry typu są wyłączone przez zawijanie. To kompiluje 'recFlatten [List [Int], Int] (Lista (Lista (1, 2, 3), Lista (4, 5))) ( recFlattenFn [Lista [Int], Int] (f = recFlattenFn [Int , Int] (f = płaskie [Int, Int] ((xs: Int) => List (xs)) // wartość domyślna ) ) ) ' – huynhjl
słusznie, zaktualizowany :) –