Created
September 25, 2014 19:40
-
-
Save nelanka/9e84b2e5514c22e7b688 to your computer and use it in GitHub Desktop.
MA Magic
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Goal: To understand what this does: | |
mapChargesOverrides(iChargeOverrides).map(validateCharge).sequence[PartialApply1Of2[ValidationNEL, String]#Apply, Charge] | |
Lets look at the types leading up to the sequence operation: | |
mapChargesOverrides(iChargeOverrides) : Seq[Charge] | |
mapChargesOverrides(iChargeOverrides).map(validateCharge) : Seq[ValidationNEL[String, Charge]] | |
We can decompose using the type alias: | |
type ValidationNEL[E, X] = Validation[NonEmptyList[E], X] | |
So we're calling sequence on a value of type: Seq[Validation[NonEmptyList[String], Charge]] | |
Looking at the type parameters for the sequence call: | |
mapChargesOverrides(iChargeOverrides).map(validateCharge).sequence[PartialApply1Of2[ValidationNEL, String]#Apply, Charge] | |
Lets see what PartialApply1Of2 does: | |
trait PartialApply1Of2[T[_, _], A] { type Apply[B] = T[A, B] } | |
ValidationNEL is a type constructor with two arguments: ValidationNEL[_, _] | |
PartialApply1Of2[T[_, _], A] matches to PartialApply1Of2[ValidationNEL[_, _], String] | |
So, T is ValidationNEL and A is String | |
What does #Apply do? | |
trait PartialApply1Of2[T[_, _], A] { type Apply[B] = T[A, B] } | |
The #Apply returns the type of ValidationNel[String, _] | |
The second type parameter is unspecified. | |
Now back to sequence: | |
sequence[N[_], B] becomes sequence[ValidationNel[String, _], Charge] | |
This is fine since ValidationNel[String, _] is a type constructor of one argument; N[_] | |
So the original line becomes: | |
mapChargesOverrides(iChargeOverrides).map(validateCharge).sequence[ValidationNel[String, _], Charge] | |
Sequence will return the following type: | |
ValidationNEL[String, M[Charge]] | |
What is M? | |
In the definition of sequence, we have: | |
trait MA[M[_], A] extends PimpedType[M[A]] with MASugar[M, A] { ... | |
def sequence[N[_], B](implicit a: A <:< N[B], t: Traverse[M], n: Applicative[N]): N[M[B]] = | |
traverse((z: A) => (z: N[B])) | |
... | |
} | |
To nail down the types, look at what .sequence is called on: Seq[Validation[NonEmptyList[String], Charge]] | |
MA[M[_], A] matches to Seq[Validation[NonEmptyList[String], Charge]] | |
So, MA is Validation, M is NonEmptyList, and A is Charge | |
Now that we know what M is, we know that there must be a Traverse[NonEmptyList] in scope, which it is: | |
implicit def NonEmptyListTraverse: Traverse[NonEmptyList] = new Traverse[NonEmptyList] { ... | |
Finally, we have our return type: ValidationNEL[String, NonEmptyList[Charge]] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment