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)
Related
In this session SystemFw gives an example of implementing State[S, A] wih vanilla scala, When follow the exmple, I run into a trouble in supplying a Applicative definition for the vanilla State type (In order to get the commands.traverse work. See code here
I tried to make a implicit def to solve the Applicative instance, but didn't figure out how to deal with the 2 type parameter.
How to implement Applicative for this type:
case class State[S, A](modify: S => (A, S)) {
def runA(initial: S): A = modify(initial)._1
def flatMap[B](f: A => State[S, B]): State[S, B] =
State { s =>
val (result, nextState) = modify(s)
f(result).modify(nextState)
}
}
Wrong code:
implicit def stateApplicative[S, A]: Applicative[State[S, A]] = new Applicative[State[S, A]] {
override def pure[A](x: A): State[A???] = ??? // error
override def ap[A, B](ff: State[A => B])(fa: State[A???]): State[B] = ??? // error
}
Basically, the solution to this problem is always fixing one type parameter.
In the case of a State you want the value inside the state to change but no the type of the state itself so you fix S.
So you can create an application for a given particular state, for example Int
type IntState[A] = State[A, Int]
implicit final val intStateApplicative: Applicative[IntState] =
new Applicative[IntState] {
// Some implementation.
}
However, after you fill the implementation you will see that the fact of knowing that S was Int was meaningless. And that we could just copy and paste the whole code if S would have been String or whatever.
So, what we want is a way to say that this works for any S, we can do that with a type lambda (i.e. a function in the type level).
type StateTypeFun[S] = { type F[A] = State[A, S] }
implicit final def stateApplicative[S]: Applicative[StateTypeFun[S]#F] =
new Applicative[StateTypeFun[S]#F] {
// Some implementation.
}
And that is how we solve this problem.
Note that the type alias is unnecessary but makes the code easier to read, but you could have done Applicative[({ type F[A] = State[A, S]})#F].
BTW, because this necessity of creating type lambdas is somewhat common in Scala 2 we have kind projector, and Scala 3 has proper syntax support for it.
I have been trying to use more abstract functional programming concepts like those from typelevel/cats for Scala.
In this specific case I am trying to eliminate the need to call map(_.flatten) after traversing some Futures.
Using the standard library it would look something like this:
def stdExample[T](things: Seq[T]): Future[Seq[T]] = {
Future.traverse(things)(futureMaybeThings[T]).map(_.flatten)
}
def futureMaybeThings[T](thing: T): Future[Option[T]] = ???
I tried using flatTraverse from typelevel/cats but the best I could get was this:
def catsExample[T](things: Seq[T]): Future[Seq[T]] = {
things.toList.flatTraverse(futureMaybeThings[T](_).map(_.toList))
}
The call to things.toList is required to get the Traversable, I can live with that one.
Since flatTraverse requires f to be C => G[F[B]] (where both C and B are T, G is Future and F is List), futureMaybeThings doesn't match without first transforming the result with map(_.toList). This ends up being worse than the other solution.
It is possible to create a function that works just on Future and TraversableOnce (since there is an implicit conversion for Option[A] => TraversableOnce[A]. Such an implementation might be like:
def flatTraverse[A, B[_], C, M[X] <: TraversableOnceWithFlatten[X, M]](in: M[A])
(fn: A => Future[B[C]])
(implicit cbf: CanBuildFrom[M[A], B[C], M[B[C]]],
asTraversable: B[C] => TraversableOnce[C],
executor: ExecutionContext): Future[M[C]] = {
Future.traverse(in)(fn).map(_.flatten)
}
This now works how I want:
def customExample[T](things: Seq[T]): Future[Seq[T]] = {
flatTraverse(things)(futureMaybeThings[T])
}
Is there a way to achieve this same thing with typelevel/cats?
Bonus: If not then what would the signature of such a function look like?
I'm trying to start using free monads in my project and I'm struggling to make it elegant.
Let's say I have two contexts (in reality I have more) - Receipt and User - both have operations on a database and I would like to keep their interpreters separate and compose them at the last moment.
For this I need to define different operations for each and combine them into one type using Coproduct.
This is what I have after days of googling and reading:
// Receipts
sealed trait ReceiptOp[A]
case class GetReceipt(id: String) extends ReceiptOp[Either[Error, ReceiptEntity]]
class ReceiptOps[F[_]](implicit I: Inject[ReceiptOp, F]) {
def getReceipt(id: String): Free[F, Either[Error, ReceiptEntity]] = Free.inject[ReceiptOp, F](GetReceipt(id))
}
object ReceiptOps {
implicit def receiptOps[F[_]](implicit I: Inject[ReceiptOp, F]): ReceiptOps[F] = new ReceiptOps[F]
}
// Users
sealed trait UserOp[A]
case class GetUser(id: String) extends UserOp[Either[Error, User]]
class UserOps[F[_]](implicit I: Inject[UserOp, F]) {
def getUser(id: String): Free[F, Either[Error, User]] = Free.inject[UserOp, F](GetUser(id))
}
object UserOps {
implicit def userOps[F[_]](implicit I: Inject[UserOp, F]): UserOps[F] = new UserOps[F]
}
When I want to write a program I can do this:
type ReceiptsApp[A] = Coproduct[ReceiptOp, UserOp, A]
type Program[A] = Free[ReceiptsApp, A]
def program(implicit RO: ReceiptOps[ReceiptsApp], UO: UserOps[ReceiptsApp]): Program[String] = {
import RO._, UO._
for {
// would like to have 'User' type here
user <- getUser("user_id")
receipt <- getReceipt("test " + user.isLeft) // user type is `Either[Error, User]`
} yield "some result"
}
The problem here is that for example user in for comprehension is of type Either[Error, User] which is understandable looking at the getUser signature.
What I would like to have is User type or stopped computation.
I know I need to somehow use an EitherT monad transformer or FreeT, but after hours of trying I don't know how to combine the types to make it work.
Can someone help?
Please let me know if more details are needed.
I've also created a minimal sbt project here, so anyone willing to help could run it: https://github.com/Leonti/free-monad-experiment/blob/master/src/main/scala/example/FreeMonads.scala
Cheers,
Leonti
After long battle with Cats:
// Receipts
sealed trait ReceiptOp[A]
case class GetReceipt(id: String) extends ReceiptOp[Either[Error, ReceiptEntity]]
class ReceiptOps[F[_]](implicit I: Inject[ReceiptOp, F]) {
private[this] def liftFE[A, B](f: ReceiptOp[Either[A, B]]) = EitherT[Free[F, ?], A, B](Free.liftF(I.inj(f)))
def getReceipt(id: String): EitherT[Free[F, ?], Error, ReceiptEntity] = liftFE(GetReceipt(id))
}
object ReceiptOps {
implicit def receiptOps[F[_]](implicit I: Inject[ReceiptOp, F]): ReceiptOps[F] = new ReceiptOps[F]
}
// Users
sealed trait UserOp[A]
case class GetUser(id: String) extends UserOp[Either[Error, User]]
class UserOps[F[_]](implicit I: Inject[UserOp, F]) {
private[this] def liftFE[A, B](f: UserOp[Either[A, B]]) = EitherT[Free[F, ?], A, B](Free.liftF(I.inj(f)))
def getUser(id: String): EitherT[Free[F, ?], Error, User] = Free.inject[UserOp, F](GetUser(id))
}
object UserOps {
implicit def userOps[F[_]](implicit I: Inject[UserOp, F]): UserOps[F] = new UserOps[F]
}
Then you write program as you want:
type ReceiptsApp[A] = Coproduct[ReceiptOp, UserOp, A]
type Program[A] = Free[ReceiptsApp, A]
def program(implicit RO: ReceiptOps[ReceiptsApp], UO: UserOps[ReceiptsApp]): Program[Either[Error, String]] = {
import RO._, UO._
(for {
// would like to have 'User' type here
user <- getUser("user_id")
receipt <- getReceipt("test " + user.isLeft) // user type is `User` now
} yield "some result").value // you have to get Free value from EitherT, or change return signature of program
}
A little explanation. Without Coproduct transformer, functions would return:
Free[F, A]
Once we add Coproduct of operations into picture, return type becomes:
Free[F[_], A]
, which works fine until we try to transform it to EitherT. If there would not be Coproduct, EitherT would look like:
EitherT[F, ERROR, A]
Where F, is Free[F, A]. But if F is Coproduct and Injection is used, intuition leads to:
EitherT[F[_], ERROR, A]
Which is wrong obviously, here we have to extract type of Coproduct. Which would lead us with kind-projector plugin to:
EitherT[Free[F, ?], ERROR, A]
Or with lambda expression:
EitherT[({type L[a] = Free[F, a]})#L, ERROR, A]
Now it is correct type to which we can lift with:
EitherT[Free[F, ?], A, B](Free.liftF(I.inj(f)))
If needed, we can simplify return type to:
type ResultEitherT[F[_], A] = EitherT[Free[F, ?], Error, A]
And use it in functions like:
def getReceipt(id: String): ResultEitherT[F[_], ReceiptEntity] = liftFE(GetReceipt(id))
The Freek library implements all the machinery required to solve your problem:
type ReceiptsApp = ReceiptOp :|: UserOp :|: NilDSL
val PRG = DSL.Make[PRG]
def program: Program[String] =
for {
user <- getUser("user_id").freek[PRG]
receipt <- getReceipt("test " + user.isLeft).freek[PRG]
} yield "some result"
As you rediscovered yourself, Free monads and the likes are not extensible without going through the complexity of coproducts. If you are looking for an elegant solution, I would suggest you have a look at Tagless Final Interpreters.
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
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)