This is a follow up to my previous question.
Suppose I need to write a function validate in order to make sure that a given list of strings consists of "a", "b", and one or more "c".
def validate(ss: List[String]): Either[NonEmptyList[MyError], Unit] = ???
Suppose I have three functions to check if a given string is "a", "b", or "c":
def validateA(str: String): Either[MyError, Unit] = ???
def validateB(str: String): Either[MyError, Unit] = ???
def validateC(str: String): Either[MyError, Unit] = ???
How to compose those functions to implement validate ?
One solution is a "parser combinators" approach. Define a monad instance for type Validator = Either[NonEmptyList[MyError], List[String]], combinators like oneOrMore similar to parser combinators etc.
I am wondering whether there is an easier solution.
I suggest you to leverage cats Validated.
Let's define some helper methods, if you really don't want to change your validateT methods signatures:
def validateA_(str: String): ValidatedNel[MyError, Unit] = validateA(str).toValidatedNel
def validateB_(str: String): ValidatedNel[MyError, Unit] = validateB(str).toValidatedNel
def validateC_(str: String): ValidatedNel[MyError, Unit] = validateC(str).toValidatedNel
Then you can implement a validate_ helper function:
import cats.data.Validated.{ invalidNel, valid }
def validate_(ss: List[String]): ValidatedNel[MyError, Unit] = ss match {
case a :: b :: c if c.nonEmpty =>
validateA_(a) combine validateB_(b) combine c.traverseU_(validateC_)
case _ => invalidNel(MyError(???)) //List too short
}
And finally implement your validate function as:
def validate(ss: List[String]): Either[NonEmptyList[MyError], Unit] =
validate_(ss).toEither
Assumptions: the input list is sorted and if it is shorter than 3 elements a specific error (e.g. list too short) is acceptable.
Looks like you could make use of Scalactic, which allows one to accumulate errors without short-circuiting the whole validation process.
This example looks quite similar to what you are trying to do. Check it out!
Related
I'm in the following situation. I would like a function to only be able to run in a given context. At the same time I would love to be able to compose these functions using the andThen syntax (It would just look much better in this case).
So here is a small example for a worksheet. I would love to be able to do it the second way.
implicit val iInt: Int = 2
def a(a: String)(implicit ctx: Int): String = a
def b(b: String)(implicit ctx: Int): String = b
val works = b(a("foo"))
val fails = a("foo") andThen b
The general question would probably be. How does one compose curried functions? But if somebody can meet the requirements described in the first paragraph I would also be interested.
This line works as you want with your definitions of a and b:
val worksToo = (a _ andThen b) ("foo")
a and b are transformed to functions (because there are not), then chained.
In ScalaZ, what is the idiomatic way to convert an Option[Validation[E, A]] to a Validation[E, Option[A]]?
For example, in the following hypothetical code:
def convert(x: Option[Validation[E, A]]): Validation[E, Option[A]] =
/* ??? */
def validateThing(thing: A): Validation[E, A] =
/* whatever */
def exampleUseCase(maybeThing: Option[Thing]): Validation[E, Option[Thing]] = {
val validated: Option[Validation[E, Thing]] = a.map(validateThing(_))
// ...
val result: Validation[E, Option[Thing]] = convert(validated)
result
}
what would the implementation of convert look like in idiomatic ScalaZ?
I can see two possible solutions here. Probably the easiest one using pattern matching on the argument, example:
def convert[A](v: Option[Validation[Throwable, A]]): Validation[Throwable, Option[A]] = {
v match {
case None => Validation.success(None)
case Some(valid) => valid.map(Some(_))
}
}
For Scalaz based solution, i was thinking about sequence, this way you need to use ValidationNel instead of Validation, to aggregate possible issues, the you can implement convert with Traversable:
def convert[A](v: Option[ValidationNel[Throwable, A]]): ValidationNel[Throwable, Option[A]] =
Traverse[Option].sequenceU(v)
Please note that in fact i'm using sequenceU instead of just sequence, it's nothing more than internal Scalaz magic for proper type inference, cause Validation has two type parameters. Hope it helps
Say I have the following function:
def getRemoteThingy(id: Id): EitherT[Future, NonEmptyList[Error], Thingy]
Given a List[Id], I can easily easily retrieve a List[Thingy] by using Traverse[List]:
val thingies: EitherT[Future, NonEmptyList[Error], List[Thingy]] =
ids.traverseU(getRemoteThingy)
It will use the Applicative instance for EitherT which will be based on flatMap so I will only get the first NonEmptyList[Error], it won't append all of them. Is that correct?
Now, if I actually want to accumulate errors, I can switch between EitherT and Validation. For example:
def thingies2: EitherT[Future, NonEmptyList[Error], List[Thingy]] =
EitherT(ids.traverseU(id => getRemoteThingy(id).validation).map(_.sequenceU.disjunction))
It works, I get all the errors at the end, but it is pretty cumbersome. I can make it simpler by using Applicative composition:
type ValidationNelError[A] = Validation[NonEmptyList[Error], A]
type FutureValidationNelError[A] = Future[ValidationNelError[A]]
implicit val App: Applicative[FutureValidationNelError] =
Applicative[Future].compose[ValidationNelError]
def thingies3: EitherT[Future, NonEmptyList[Error], List[Thingy]] =
EitherT(
ids.traverse[FutureValidationNelError, Thingy](id =>
getRemoteThingy(id).validation
).map(_.disjunction)
)
Longer than the others but all the plumbing can easily be shared across the code base.
What do you think of my solutions? Is there a more elegant way to solve this problem? How do you usually tackle it?
Thank you very much.
EDIT:
I have kind of a mad man solution using natural transformations to pimp Traversable. You apparently need type aliases for it to work, that's why I redefined getRemoteThingy:
type FutureEitherNelError[A] = EitherT[Future, NonEmptyList[String], A]
def getRemoteThingy2(id: Id): FutureEitherNelError[Thingy] = getRemoteThingy(id)
implicit val EitherTToValidation = new NaturalTransformation[FutureEitherNelError, FutureValidationNelError] {
def apply[A](eitherT: FutureEitherNelError[A]): FutureValidationNelError[A] = eitherT.validation
}
implicit val ValidationToEitherT = new NaturalTransformation[FutureValidationNelError, FutureEitherNelError] {
def apply[A](validation: FutureValidationNelError[A]): FutureEitherNelError[A] = EitherT(validation.map(_.disjunction))
}
implicit class RichTraverse[F[_], A](fa: F[A]) {
def traverseUsing[H[_]]: TraverseUsing[F, H, A] = TraverseUsing(fa)
}
case class TraverseUsing[F[_], H[_], A](fa: F[A]) {
def apply[G[_], B](f: A => G[B])(implicit GtoH: G ~> H, HtoG: H ~> G, A: Applicative[H], T: Traverse[F]): G[F[B]] =
HtoG(fa.traverse(a => GtoH(f(a))))
}
def thingies4: FutureEitherNelError[List[Thingy]] =
ids.traverseUsing[FutureValidationNelError](getRemoteThingy2)
I want to be able to have a map implementation of type [String,Any] in which i can store objects of different classes then i want to be able to do
import app.User;
....
usr = map.getAs("user",User)// with usr being an object of Class/Object User. If user is not of that type it throws an exception.
where user was previously stored in the map.
Is this possible?
I can even be a standalone method e.g
usr = getAs(map,"user",User)
Thanks
You can use ClassTag. I don't have a lot of experience with it, but something like that should work:
def getAs[T: ClassTag](m: Map[String, Any], key: String): T =
m(key).asInstanceOf[T]
Usage:
val map = Map[String, Any]("one" -> 1, "hello"-> "world")
getAs[String](map, "hello")
res1: String = world
I let you deal with the exception, you can simply wrap the asInstanceOf in a Try, or whichever strategy you prefer. I also recommend changing the return type to Option[T].
Thanks vptheron. That definitely works.
I took your advice and did it using Option[T] and used matching instead.
def getAsOption[T: ClassTag](m: Map[String, Any], key: String): Option[T] =
m.get(key) match {
case x : Option[T] => x
case _ => None
}
I wanted a mechanism to pass random stuff in the play framework and this looks like a good solution for me though the purists wont like it.
I think using TypeTag will do better job unless you will never cast the values into generic types.
import scala.reflect.runtime.universe._
trait Typed[A] {
val value: A
implicit val ttag: TypeTag[A]
}
def cast[A, B: TypeTag](v: Typed[A]): Option[B] = {
val tA = typeOf[A](v.ttag)
val tB = typeOf[B]
def vB = v.value.asInstanceOf[B]
if (tA <:< tB) Some(vB) else None
}
def getTyped[A, B, C: TypeTag](map: Map[A, Typed[B]], key: A): Option[C] = {
map get key flatMap cast[B, C]
}
I have the following use case which occurs often in my code:
A Collection[A]
An implicit conversion A to B
and I want to obtain a collection of B. I can use implicitly like the following:
case class Items(underlying:List[B])
import B._
def apply(a:List[A]):Items = {
val listOfB= a.map {implicitly[A=>B]}
Items(listOfB)
}
What is the most elegant way to do that in Scala, maybe with the help of Scalaz of doing the same?
Edit: the goal of my question is to find an idiomatic way, a common approach among libraries/developers. In such a sense developing my own pimp-my-library solution is something I dislike, because other people writing my code would not know the existence of this conversion and would not use it, and they will rewrite their own. I favour using a library approach for this common functions and that's why I am wondering whether in Scalaz it exists such a feature.
It's pretty straightforward if you know the types. First implicit conversion from A to B:
implicit def conversion(a: A): B = //...
then you need implicit conversion from List[S] to List[T] where S and T are arbitrary types for which implicit conversion from S to T exists:
implicit def convList[S, T](input: List[S])(implicit c: S => T): List[T] =
input map c
This should then work:
val listOfA: List[A] = //...
val listOfB: List[B] = listOfA
which is resolved by the compiler to:
val listOfB: List[B] = convList(listOfA)(conversion)
where S is A and T is B.
I wouldn't use an implicit conversion here, but a view bound in the class:
case class Foo(x: Int)
case class Bar(y: Int)
implicit def foo2Bar(foo: Foo) = Bar(foo.x)
case class Items[A <% Bar](xs: List[A]) {
def apply(x: Int): Bar = xs(x)
}
You can now create an instance of Items with a list of Foo and internally use them, as if they were Bars.
scala> Items(List(Foo(1)))
res8: Items[Foo] = Items(List(Foo(1)))
scala> res8(0)
res9: Bar = Bar(1)
edit:
Some clarification, on why I would not use an implicit conversion:
Implicit conversions can be dangerous, when they are in scope and accidentally convert things, that they shouldn't convert. I would always convert stuff explicitly or via view bounds, because then I can control it, also implicit conversion may shrink the size of your code, but also makes it harder to understand for others. I would only use implicit conversion for the 'extend my library' pattern.
edit2:
You could however add a method to the collection types, that does this conversion, if such a method is in scope:
trait Convertable[M[A], A] {
def convertTo[B](implicit f: A => B): M[B]
}
implicit def list2Convertable[A](xs: List[A]) = new Convertable[List, A] {
def convertTo[B](implicit f: A => B) = xs.map(f)
}
scala> implicit def int2String(x: Int) = x.toString
int2String: (x: Int)String
scala> List(1,2,3).convertTo[String]
res0: List[String] = List(1, 2, 3)
Instead of using another implicit conversion here, I would probably use a typeclass instead, but I think you get the basic idea.
Works starting with Scala 2.10:
implicit class ListOf[A](val list: List[A]) {
def of[B](implicit f: A => B): List[B] = list map f
}
implicit def int2String(i: Int) = i.toString
// Usage
List(1,2,3).of[String]
In my code, I'm using a more general version adapted from Tomasz' solution above which handles all Traversable instances
/** Implicit conversion for Traversable instances where the elements are convertable */
implicit def convTrav[S, T, I[S] <: Traversable[S]](input: I[S])(implicit c: S => T): I[T] =
(input map c).asInstanceOf[I[T]]
(This is working for me, although I'm keen to know if any more experienced Scala programmers think this is a bad idea for any reason, apart from the usual caveats about implicit conversions)