Flattening mixed nested monads in cats (composing complex Kleislis) - scala

I would like to understand how I should compose Kleislis that return "complex" types (e.g. F[Either[A,B]]). Here's an example of what I mean:
This is a simple case - given two Kleislis
val parseRegistration: Kleisli[Result, Auth.Registration, Auth.Registration] = ???
val hashPassword: Kleisli[Result, Auth.Registration, Auth.Registration] = ???
I can compose them in this way:
val validateAndHash = parseRegistration andThen hashPassword
And all is fine.
However, given more complex Kleisli types (where the return value is an Either[A, B]), I'm not able to compose them directly (because I ended up with F[Either[A,B]] where a Kleisli expects only F[A]).
// relevant type definitions
final case class ServiceError(kind: ErrorKind, message: String = "", cause: Option[Throwable] = None)
final type Result[A] = Either[ServiceError, A]
final case class Registration(email: String, password: String)
final case class Registered(session: Session)
val createUser: Kleisli[F, Auth.Registration, Result[Long]] = ???
val createSession: Kleisli[F, Long, Result[Session]] = ???
// does not compile (no overloaded alternatives match the arguments) - I expected this as
// createUser returns F[Result[Long]] and the createSession Kleisli expects only F[Long]
val createUserAndSession = createUser andThen createSession
Ok, so as expected. Then, instead of composing them, I tried simply performing nested maps:
val r1 = validateAndHash(info) // Result[Auth.Registration]
val r2 = r1.map(i => createUser(i)) // Either[ServiceError, F[Result[Long]]]
val r3 = r2.map(_.map(_.map(uid => createSession(uid).map(_.map(Auth.Registered.apply)))))
// Now I've got an Either[ServiceError, F[Either[ServiceError, F[Either[ServiceError, Auth.Registered]]]]]
// in r3! I wanted to end up with F[Result[Auth.Registered]]
So I've ended up causing increasing nesting and flatten doesn't seem to help because F and Result can't be flattened into each other.
I'm sure this is something the seasoned scala cats programmers encounter all the time, so I'd appreciate it if you could help me understand how I can avoid getting myself into this mess?
EDIT:
I have now defined a function to invert the nested wrapper types so they can then be flattened:
def invert[S, F[_]: Monad, V](e: Either[S, F[V]]): F[Either[S, V]] =
e match {
case Left(s) => Monad[F].pure(Left(s))
case Right(fv) => fv.map(Right(_))
}
This allows me to do this:
val r1 = validateAndHash(info)
val r2 = invert(r1.map(i => createUser(i))).map(_.flatten)
val r3 = r2.map( i => invert(i.map(uid => createSession(uid).map(_.map(Auth.Registered.apply)))).map(_.flatten))
val r4 = Monad[F].flatten(r3)
Which seems... clumsy? And too specific to Either. Is there a cleaner way to do this using something built in to cats?

I would rather compose values than play with Kleisli, especially since EitherT makes this pretty simple.
First, let's refactor createUser & createSession to be normal methods:
def createUser[F[_]](registration: Registration): F[Result[Long]] = ???
def createSession[F[_]](long: Long): F[Result[Session]] = ???
And now let's implement createUserAndSession
import cats.Monad
import cats.data.EitherT
def createUserAndSession[F[_]](registration: Registration)(implicit ev: Monad[F]): F[Result[Session]] =
EitherT(createUser(registration)).flatMapF(createSession).value

Related

Convert Seq[Try[Option(String, Any)]] into Try[Option[Map[String, Any]]]

How to conveniently convert Seq[Try[Option[String, Any]]] into Try[Option[Map[String, Any]]].
If any Try before convert throws an exception, the converted Try should throw as well.
Assuming that the input type has a tuple inside the Option then this should give you the result you want:
val in: Seq[Try[Option[(String, Any)]]] = ???
val out: Try[Option[Map[String,Any]]] = Try(Some(in.flatMap(_.get).toMap))
If any of the Trys is Failure then the outer Try will catch the exception raised by the get and return Failure
The Some is there to give the correct return type
The get extracts the Option from the Try (or raises an exception)
Using flatMap rather than map removes the Option wrapper, keeping all Some values and discaring None values, giving Seq[(String, Any)]
The toMap call converts the Seq to a Map
Here is something that's not very clean but may help get you started. It assumes Option[(String,Any)], returns the first Failure if there are any in the input Seq and just drops None elements.
foo.scala
package foo
import scala.util.{Try,Success,Failure}
object foo {
val x0 = Seq[Try[Option[(String, Any)]]]()
val x1 = Seq[Try[Option[(String, Any)]]](Success(Some(("A",1))), Success(None))
val x2 = Seq[Try[Option[(String, Any)]]](Success(Some(("A",1))), Success(Some(("B","two"))))
val x3 = Seq[Try[Option[(String, Any)]]](Success(Some(("A",1))), Success(Some(("B","two"))), Failure(new Exception("bad")))
def f(x: Seq[Try[Option[(String, Any)]]]) =
x.find( _.isFailure ).getOrElse( Success(Some(x.map( _.get ).filterNot( _.isEmpty ).map( _.get ).toMap)) )
}
Example session
bash-3.2$ scalac foo.scala
bash-3.2$ scala -classpath .
Welcome to Scala 2.13.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_66).
Type in expressions for evaluation. Or try :help.
scala> import foo.foo._
import foo.foo._
scala> f(x0)
res0: scala.util.Try[Option[Equals]] = Success(Some(Map()))
scala> f(x1)
res1: scala.util.Try[Option[Equals]] = Success(Some(Map(A -> 1)))
scala> f(x2)
res2: scala.util.Try[Option[Equals]] = Success(Some(Map(A -> 1, B -> two)))
scala> f(x3)
res3: scala.util.Try[Option[Equals]] = Failure(java.lang.Exception: bad)
scala> :quit
If you're willing to use a functional support library like Cats then there are two tricks that can help this along:
Many things like List and Try are traversable, which means that (if Cats's implicits are in scope) they have a sequence method that can swap two types, for example converting List[Try[T]] to Try[List[T]] (failing if any of the items in the list are failure).
Almost all of the container types support a map method that can operate on the contents of a container, so if you have a function from A to B then map can convert a Try[A] to a Try[B]. (In Cats language they are functors but the container-like types in the standard library generally have map already.)
Cats doesn't directly support Seq, so this answer is mostly in terms of List instead.
Given that type signature, you can iteratively sequence the item you have to in effect push the list type down one level in the type chain, then map over that container to work on its contents. That can look like:
import cats.implicits._
import scala.util._
def convert(listTryOptionPair: List[Try[Option[(String, Any)]]]): Try[
Option[Map[String, Any]]
] = {
val tryListOptionPair = listTryOptionPair.sequence
tryListOptionPair.map { listOptionPair =>
val optionListPair = listOptionPair.sequence
optionListPair.map { listPair =>
Map.from(listPair)
}
}
}
https://scastie.scala-lang.org/xbQ8ZbkoRSCXGDJX0PgJAQ has a slightly more complete example.
One way to approach this is by using a foldLeft:
// Let's say this is the object you're trying to convert
val seq: Seq[Try[Option[(String, Any)]]] = ???
seq.foldLeft(Try(Option(Map.empty[String, Any]))) {
case (acc, e) =>
for {
accOption <- acc
elemOption <- e
} yield elemOption match {
case Some(value) => accOption.map(_ + value)
case None => accOption
}
}
You start off with en empty Map. You then use a for comprehension to go through the current map and element and finally you add a new tuple in the map if present.
The following solutions is based on this answer to the point that almost makes the question a duplicate.
Method 1: Using recursion
def trySeqToMap1[X,Y](trySeq : Seq[Try[Option[(X, Y)]]]) : Try[Option[Map[X,Y]]] = {
def helper(it : Iterator[Try[Option[(X,Y)]]], m : Map[X,Y] = Map()) : Try[Option[Map[X,Y]]] = {
if(it.hasNext) {
val x = it.next()
if(x.isFailure)
Failure(x.failed.get)
else if(x.get.isDefined)
helper(it, m + (x.get.get._1-> x.get.get._2))
else
helper(it, m)
} else Success(Some(m))
}
helper(trySeq.iterator)
}
Method 2: directly pattern matching in case you are able to get a stream or a List instead:
def trySeqToMap2[X,Y](trySeq : LazyList[Try[Option[(X, Y)]]], m : Map[X,Y]= Map.empty[X,Y]) : Try[Option[Map[X,Y]]] =
trySeq match {
case Success(Some(h)) #:: tail => trySeqToMap2(tail, m + (h._1 -> h._2))
case Success(None) #:: tail => tail => trySeqToMap2(tail, m)
case Failure(f) #:: _ => Failure(f)
case _ => Success(Some(m))
}
note: this answer was previously using different method signatures. It has been updated to conform to the signature given in the question.

Scala Cats Accumulating Errors and Successes with Ior

I am trying to use Cats datatype Ior to accumulate both errors and successes of using a service (which can return an error).
def find(key: String): F[Ior[NonEmptyList[Error], A]] = {
(for {
b <- service.findByKey(key)
} yield b.rightIor[NonEmptyList[Error]])
.recover {
case e: Error => Ior.leftNel(AnotherError)
}
}
def findMultiple(keys: List[String]): F[Ior[NonEmptyList[Error], List[A]]] = {
keys map find reduce (_ |+| _)
}
My confusion lies in how to combine the errors/successes. I am trying to use the Semigroup combine (infix syntax) to combine with no success. Is there a better way to do this? Any help would be great.
I'm going to assume that you want both all errors and all successful results. Here's a possible implementation:
class Foo[F[_]: Applicative, A](find: String => F[IorNel[Error, A]]) {
def findMultiple(keys: List[String]): F[IorNel[Error, List[A]]] = {
keys.map(find).sequence.map { nelsList =>
nelsList.map(nel => nel.map(List(_)))
.reduceOption(_ |+| _).getOrElse(Nil.rightIor)
}
}
}
Let's break it down:
We will be trying to "flip" a List[IorNel[Error, A]] into IorNel[Error, List[A]]. However, from doing keys.map(find) we get List[F[IorNel[...]]], so we need to also "flip" it in a similar fashion first. That can be done by using .sequence on the result, and is what forces F[_]: Applicative constraint.
N.B. Applicative[Future] is available whenever there's an implicit ExecutionContext in scope. You can also get rid of F and use Future.sequence directly.
Now, we have F[List[IorNel[Error, A]]], so we want to map the inner part to transform the nelsList we got. You might think that sequence could be used there too, but it can not - it has the "short-circuit on first error" behavior, so we'd lose all successful values. Let's try to use |+| instead.
Ior[X, Y] has a Semigroup instance when both X and Y have one. Since we're using IorNel, X = NonEmptyList[Z], and that is satisfied. For Y = A - your domain type - it might not be available.
But we don't want to combine all results into a single A, we want Y = List[A] (which also always has a semigroup). So, we take every IorNel[Error, A] we have and map A to a singleton List[A]:
nelsList.map(nel => nel.map(List(_)))
This gives us List[IorNel[Error, List[A]], which we can reduce. Unfortunately, since Ior does not have a Monoid, we can't quite use convenient syntax. So, with stdlib collections, one way is to do .reduceOption(_ |+| _).getOrElse(Nil.rightIor).
This can be improved by doing few things:
x.map(f).sequence is equivalent to doing x.traverse(f)
We can demand that keys are non-empty upfront, and give nonempty result back too.
The latter step gives us Reducible instance for a collection, letting us shorten everything by doing reduceMap
class Foo2[F[_]: Applicative, A](find: String => F[IorNel[Error, A]]) {
def findMultiple(keys: NonEmptyList[String]): F[IorNel[Error, NonEmptyList[A]]] = {
keys.traverse(find).map { nelsList =>
nelsList.reduceMap(nel => nel.map(NonEmptyList.one))
}
}
}
Of course, you can make a one-liner out of this:
keys.traverse(find).map(_.reduceMap(_.map(NonEmptyList.one)))
Or, you can do the non-emptiness check inside:
class Foo3[F[_]: Applicative, A](find: String => F[IorNel[Error, A]]) {
def findMultiple(keys: List[String]): F[IorNel[Error, List[A]]] = {
NonEmptyList.fromList(keys)
.map(_.traverse(find).map { _.reduceMap(_.map(List(_))) })
.getOrElse(List.empty[A].rightIor.pure[F])
}
}
Ior is a good choice for warning accumulation, that is errors and a successful value. But, as mentioned by Oleg Pyzhcov, Ior.Left case is short-circuiting. This example illustrates it:
scala> val shortCircuitingErrors = List(
Ior.leftNec("error1"),
Ior.bothNec("warning2", 2),
Ior.bothNec("warning3", 3)
).sequence
shortCircuitingErrors: Ior[Nec[String], List[Int]]] = Left(Chain(error1))
One way to accumulate both errors and successes is to convert all your Left cases into Both. One approach is using Option as right type and converting Left(errs) values into Both(errs, None). After calling .traverse, you end up with optList: List[Option] on the right side and you can flatten it with optList.flatMap(_.toList) to filter out None values.
class Error
class KeyValue
def find(key: String): Ior[Nel[Error], KeyValue] = ???
def findMultiple(keys: List[String]): Ior[Nel[Error], List[KeyValue]] =
keys
.traverse { k =>
val ior = find(k)
ior.putRight(ior.right)
}
.map(_.flatMap(_.toList))
Or more succinctly:
def findMultiple(keys: List[String]): Ior[Nel[Error], List[KeyValue]] =
keys.flatTraverse { k =>
val ior = find(k)
ior.putRight(ior.toList) // Ior[A,B].toList: List[B]
}

Scala - evaluate function calls sequentially until one return

I have a few 'legacy' endpoints that can return the Data I'm looking for.
def mainCall(id): Data {
maybeMyDataInEndpoint1(id: UUID): DataA
maybeMyDataInEndpoint2(id: UUID): DataB
maybeMyDataInEndpoint3(id: UUID): DataC
}
null can be returned if no DataX found
return types for each method are different. There are a convert method that converting each DataX to unified Data.
The endpoints are not Scala-ish
What is the best Scala approach to evaluate those method calls sequentially until I have the value I need?
In pseudo I would do something like:
val myData = maybeMyDataInEndpoint1 getOrElse maybeMyDataInEndpoint2 getOrElse maybeMyDataInEndpoint3
I'd use an easier approach, though the other Answers use more elaborate language features.
Just use Option() to catch the null, chain with orElse. I'm assuming methods convertX(d:DataX):Data for explicit conversion. As it might not be found at all we return an Option
def mainCall(id: UUID): Option[Data] {
Option(maybeMyDataInEndpoint1(id)).map(convertA)
.orElse(Option(maybeMyDataInEndpoint2(id)).map(convertB))
.orElse(Option(maybeMyDataInEndpoint3(id)).map(convertC))
}
Maybe You can lift these methods as high order functions of Lists and collectFirst, like:
val fs = List(maybeMyDataInEndpoint1 _, maybeMyDataInEndpoint2 _, maybeMyDataInEndpoint3 _)
val f = (a: UUID) => fs.collectFirst {
case u if u(a) != null => u(a)
}
r(myUUID)
The best Scala approach IMHO is to do things in the most straightforward way.
To handle optional values (or nulls from Java land), use Option.
To sequentially evaluate a list of methods, fold over a Seq of functions.
To convert from one data type to another, use either (1.) implicit conversions or (2.) regular functions depending on the situation and your preference.
(Edit) Assuming implicit conversions:
def legacyEndpoint[A](endpoint: UUID => A)(implicit convert: A => Data) =
(id: UUID) => Option(endpoint(id)).map(convert)
val legacyEndpoints = Seq(
legacyEndpoint(maybeMyDataInEndpoint1),
legacyEndpoint(maybeMyDataInEndpoint2),
legacyEndpoint(maybeMyDataInEndpoint3)
)
def mainCall(id: UUID): Option[Data] =
legacyEndpoints.foldLeft(Option.empty[Data])(_ orElse _(id))
(Edit) Using explicit conversions:
def legacyEndpoint[A](endpoint: UUID => A)(convert: A => Data) =
(id: UUID) => Option(endpoint(id)).map(convert)
val legacyEndpoints = Seq(
legacyEndpoint(maybeMyDataInEndpoint1)(fromDataA),
legacyEndpoint(maybeMyDataInEndpoint2)(fromDataB),
legacyEndpoint(maybeMyDataInEndpoint3)(fromDataC)
)
... // same as before
Here is one way to do it.
(1) You can make your convert methods implicit (or wrap them into implicit wrappers) for convenience.
(2) Then use Stream to build chain from method calls. You should give type inference a hint that you want your stream to contain Data elements (not DataX as returned by legacy methods) so that appropriate implicit convert will be applied to each result of a legacy method call.
(3) Since Stream is lazy and evaluates its tail "by name" only first method gets called so far. At this point you can apply lazy filter to skip null results.
(4) Now you can actually evaluate chain, getting first non-null result with headOption
(HACK) Unfortunately, scala type inference (at the time of writing, v2.12.4) is not powerful enough to allow using #:: stream methods, unless you guide it every step of the way. Using cons makes inference happy but is cumbersome. Also, building stream using vararg apply method of companion object is not an option too, since scala does not support "by-name" varargs yet. In my example below I use combination of stream and toLazyData methods. stream is a generic helper, builds streams from 0-arg functions. toLazyData is an implicit "by-name" conversion designed to interplay with implicit convert functions that convert from DataX to Data.
Here is the demo that demonstrates the idea with more detail:
object Demo {
case class Data(value: String)
class DataA
class DataB
class DataC
def maybeMyDataInEndpoint1(id: String): DataA = {
println("maybeMyDataInEndpoint1")
null
}
def maybeMyDataInEndpoint2(id: String): DataB = {
println("maybeMyDataInEndpoint2")
new DataB
}
def maybeMyDataInEndpoint3(id: String): DataC = {
println("maybeMyDataInEndpoint3")
new DataC
}
implicit def convert(data: DataA): Data = if (data == null) null else Data(data.toString)
implicit def convert(data: DataB): Data = if (data == null) null else Data(data.toString)
implicit def convert(data: DataC): Data = if (data == null) null else Data(data.toString)
implicit def toLazyData[T](value: => T)(implicit convert: T => Data): (() => Data) = () => convert(value)
def stream[T](xs: (() => T)*): Stream[T] = {
xs.toStream.map(_())
}
def main (args: Array[String]) {
val chain = stream(
maybeMyDataInEndpoint1("1"),
maybeMyDataInEndpoint2("2"),
maybeMyDataInEndpoint3("3")
)
val result = chain.filter(_ != null).headOption.getOrElse(Data("default"))
println(result)
}
}
This prints:
maybeMyDataInEndpoint1
maybeMyDataInEndpoint2
Data(Demo$DataB#16022d9d)
Here maybeMyDataInEndpoint1 returns null and maybeMyDataInEndpoint2 needs to be invoked, delivering DataB, maybeMyDataInEndpoint3 never gets invoked since we already have the result.
I think #g.krastev's answer is perfectly good for your use case and you should accept that. I'm just expending a bit on it to show how you can make the last step slightly better with cats.
First, the boilerplate:
import java.util.UUID
final case class DataA(i: Int)
final case class DataB(i: Int)
final case class DataC(i: Int)
type Data = Int
def convertA(a: DataA): Data = a.i
def convertB(b: DataB): Data = b.i
def convertC(c: DataC): Data = c.i
def maybeMyDataInEndpoint1(id: UUID): DataA = DataA(1)
def maybeMyDataInEndpoint2(id: UUID): DataB = DataB(2)
def maybeMyDataInEndpoint3(id: UUID): DataC = DataC(3)
This is basically what you have, in a way that you can copy/paste in the REPL and have compile.
Now, let's first declare a way to turn each of your endpoints into something safe and unified:
def makeSafe[A, B](evaluate: UUID ⇒ A, f: A ⇒ B): UUID ⇒ Option[B] =
id ⇒ Option(evaluate(id)).map(f)
With this in place, you can, for example, call the following to turn maybeMyDataInEndpoint1 into a UUID => Option[A]:
makeSafe(maybeMyDataInEndpoint1, convertA)
The idea is now to turn your endpoints into a list of UUID => Option[A] and fold over that list. Here's your list:
val endpoints = List(
makeSafe(maybeMyDataInEndpoint1, convertA),
makeSafe(maybeMyDataInEndpoint2, convertB),
makeSafe(maybeMyDataInEndpoint3, convertC)
)
You can now fold on it manually, which is what #g.krastev did:
def mainCall(id: UUID): Option[Data] =
endpoints.foldLeft(None: Option[Data])(_ orElse _(id))
If you're fine with a cats dependency, the notion of folding over a list of options is just a concrete use case of a common pattern (the interaction of Foldable and Monoid):
import cats._
import cats.implicits._
def mainCall(id: UUID): Option[Data] = endpoints.foldMap(_(id))
There are other ways to make this nicer still, but they might be overkill in this context - I'd probably declare a type class to turn any type into a Data, say, to give makeSafe a cleaner type signature.

How to accumulate errors in Either?

Suppose I have few case classes and functions to test them:
case class PersonName(...)
case class Address(...)
case class Phone(...)
def testPersonName(pn: PersonName): Either[String, PersonName] = ...
def testAddress(a: Address): Either[String, Address] = ...
def testPhone(p: Phone): Either[String, Phone] = ...
Now I define a new case class Person and a test function, which fails fast.
case class Person(name: PersonName, address: Address, phone: Phone)
def testPerson(person: Person): Either[String, Person] = for {
pn <- testPersonName(person.name).right
a <- testAddress(person.address).right
p <- testPhone(person.phone).right
} yield person;
Now I would like function testPerson to accumulate the errors rather than just fail fast.
I would like testPerson to always execute all those test* functions and return Either[List[String], Person]. How can I do that ?
You want to isolate the test* methods and stop using a comprehension!
Assuming (for whatever reason) that scalaz isn't an option for you... it can be done without having to add the dependency.
Unlike a lot of scalaz examples, this is one where the library doesn't reduce verbosity much more than "regular" scala can:
def testPerson(person: Person): Either[List[String], Person] = {
val name = testPersonName(person.name)
val addr = testAddress(person.address)
val phone = testPhone(person.phone)
val errors = List(name, addr, phone) collect { case Left(err) => err }
if(errors.isEmpty) Right(person) else Left(errors)
}
Scala's for-comprehensions (which desugar to a combination of calls to flatMap and map) are designed to allow you to sequence monadic computations in such a way that you have access to the result of earlier computations in subsequent steps. Consider the following:
def parseInt(s: String) = try Right(s.toInt) catch {
case _: Throwable => Left("Not an integer!")
}
def checkNonzero(i: Int) = if (i == 0) Left("Zero!") else Right(i)
def inverse(s: String): Either[String, Double] = for {
i <- parseInt(s).right
v <- checkNonzero(i).right
} yield 1.0 / v
This won't accumulate errors, and in fact there's no reasonable way that it could. Suppose we call inverse("foo"). Then parseInt will obviously fail, which means there's no way we can have a value for i, which means there's no way we could move on to the checkNonzero(i) step in the sequence.
In your case your computations don't have this kind of dependency, but the abstraction you're using (monadic sequencing) doesn't know that. What you want is an Either-like type that isn't monadic, but that is applicative. See my answer here for some details about the difference.
For example, you could write the following with Scalaz's Validation without changing any of your individual validation methods:
import scalaz._, syntax.apply._, syntax.std.either._
def testPerson(person: Person): Either[List[String], Person] = (
testPersonName(person.name).validation.toValidationNel |#|
testAddress(person.address).validation.toValidationNel |#|
testPhone(person.phone).validation.toValidationNel
)(Person).leftMap(_.list).toEither
Although of course this is more verbose than necessary and is throwing away some information, and using Validation throughout would be a little cleaner.
As #TravisBrown is telling you, for comprehensions don't really mix with error accumulations. In fact, you generally use them when you don't want fine grained error control.
A for comprehension will "short-circuit" itself on the first error found, and this is almost always what you want.
The bad thing you are doing is using String to do flow control of exceptions. You should at all times use Either[Exception, Whatever] and fine tune logging with scala.util.control.NoStackTrace and scala.util.NonFatal.
There are much better alternatives, specifically:
scalaz.EitherT and scalaz.ValidationNel.
Update:(this is incomplete, I don't know exactly what you want). You have better options than matching, such as getOrElse and recover.
def testPerson(person: Person): Person = {
val attempt = Try {
val pn = testPersonName(person.name)
val a = testAddress(person.address)
testPhone(person.phone)
}
attempt match {
case Success(person) => //..
case Failure(exception) => //..
}
}
Starting in Scala 2.13, we can partitionMap a List of Eithers in order to partition elements based on their Either's side.
// def testName(pn: Name): Either[String, Name] = ???
// def testAddress(a: Address): Either[String, Address] = ???
// def testPhone(p: Phone): Either[String, Phone] = ???
List(testName(Name("name")), testAddress(Address("address")), testPhone(Phone("phone")))
.partitionMap(identity) match {
case (Nil, List(name: Name, address: Address, phone: Phone)) =>
Right(Person(name, address, phone))
case (left, _) =>
Left(left)
}
// Either[List[String], Person] = Left(List("wrong name", "wrong phone"))
// or
// Either[List[String], Person] = Right(Person(Name("name"), Address("address"), Phone("phone")))
If the left side is empty, then no elements were Left and thus we can build a Person out of the Right elements.
Otherwise, we return a Left List of the Left values.
Details of the intermediate step (partitionMap):
List(Left("bad name"), Right(Address("addr")), Left("bad phone"))
.partitionMap(identity)
// (List[String], List[Any]) = (List("bad name", "bad phone"), List[Any](Address("addr")))

Acquiring 2 implicits for scalacheck function

I am using scalacheck and am in the middle of a generic-programming soup right now. The official guide shows this example:
def matrix[T](g: Gen[T]): Gen[Seq[Seq[T]]] = Gen.sized { size =>
val side = scala.math.sqrt(size).asInstanceOf[Int]
Gen.listOfN(side, Gen.listOfN(side, g))
}
Meanwhile, for my test I require a matrix of type Array[Array[T]]. I tried with the following function:
def matrix[T](g: Gen[T]): Gen[Array[Array[T]]] = Gen.sized { size =>
val side = scala.math.sqrt(size).asInstanceOf[Int]
val g1 = Gen.containerOfN[Array, T](side, g)
Gen.containerOfN[Array, Array[T]](side, g1)
}
Here, I run into trouble. The compiler says:
Multiple markers at this line
- not enough arguments for method containerOfN: (implicit b: org.scalacheck.util.Buildable[T,Array])org.scalacheck.Gen[Array[T]].
Unspecified value parameter b.
- could not find implicit value for parameter b: org.scalacheck.util.Buildable[T,Array]
- could not find implicit value for parameter b: org.scalacheck.util.Buildable[T,Array]
- not enough arguments for method containerOfN: (implicit b: org.scalacheck.util.Buildable[T,Array])org.scalacheck.Gen[Array[T]].
Unspecified value parameter b.
I understand that stuff like this is usually remedied by adding implicit parameters to the function, however, i havent made this work yet.
I usually encounter this error when building generic arrays, as an example:
def build[T](n:Int)(implicit m:ClassManifest[T]) = Array.ofDim[T](n)
but, I am afraid I don't fully understand what is happening or why this is needed.
Can someone explain how to make the correct matrix-function along with an example of usage in scalacheck? A thorough explanation of the details about building sequences with implicit class manifests would be very welcome!
edit
import org.scalacheck.util.Buildable._
def matrix[T](g: Gen[T])(implicit b: Buildable[T, Array]): Gen[Array[Array[T]]] = Gen.sized { size =>
val side = scala.math.sqrt(size).asInstanceOf[Int]
val g1 = Gen.containerOfN[Array, T](side, g)
Gen.containerOfN[Array, Array[T]](side, g1)
}
Still doesn't work. Need implicit for Buildable[Array[T],Array]... Don't know how to get this because I can only add 1 implicit argument :/
You're almost there. The important part of the error is could not find implicit value for parameter b: org.scalacheck.util.Buildable[T,Array]
Looking at the method definition of containerOfN
def containerOfN[C[_],T](n: Int, g: Gen[T])(implicit b: Buildable[T,C]): Gen[C[T]] = ...
So, there's your missing argument. You need an implicit argument of type Buildable[T,Array]. Following through to where Buildable is defined in the scalacheck sources, I found that there was an object (org.scalacheck.util.Buildable) that provides implicits that provide Buildables for the common collection types which includes Array. So all you need to bring that into scope. You can do this with:
import org.scalacheck.util.Buildable._
def matrix[T](g: Gen[T]): Gen[Array[Array[T]]] = Gen.sized { size =>
val bT = implicitly[Buildable[T, Array]]
val bArrayT = implicitly[Buildable[Array[T], Array]]
val side = scala.math.sqrt(size).asInstanceOf[Int]
val g1 = Gen.containerOfN[Array, T](side, g)
Gen.containerOfN[Array, Array[T]](side, g1)
}
Or
import org.scalacheck.util.Buildable._
def matrix[T](g: Gen[T])(implicit bT: Buildable[T, Array], bArrayT: Buildable[Array[T], Array]): Gen[Array[Array[T]]] = Gen.sized { size =>
...
}
The particular implicit you need in org.scalacheck.util.Buildable is:
implicit def buildableArray[T](implicit cm: ClassManifest[T]) =
new Buildable[T,Array] {
def builder = mutable.ArrayBuilder.make[T]
}