I am using akka streams. Can we add values from a map to an existing source in scala? I want to merge all the values from a Future[Map[String, A]] and a source of A Source[A,_] which are not already in the source. My method signature is:
case class A(id: String, someValue: String)
def addValuesToExistingSource(mySource: Source[A,_], myMapFuture: Future[Map[String, A]]): Source[A, _] = {
..//This is to be implemented
}
Thanks.
Is this what you are looking for?
def addValuesToExistingSource(mySource: Source[A, _], myMapFuture: Future[Map[String, A]]): Source[A, _] = {
//Change logic for values here
val sf = Source.futureSource(myMapFuture.map(map => Source(map.values.toList)))
Source.combine(mySource, sf)(Concat(_))
}
I assume that the keys of that map represent "ids" as in A.id. That would be much easier to understand if you'd introduce a typedef:
type Id = String
case class A(id: Id, someValue: String)
If I understood correctly, you want a source that first emits all As from mySource and then (after mySource completed) emits all those values from the Map (from the Future) for which the key does not match any of the ids from the items of mySource?
Approach one: keep removing entries from the map and then emit the rest when mySource completes:
def addValuesToExistingSource(
mySource: Source[A, _],
myMap: Map[Id, A]
): Source[A, _] = {
// map to Right and append a single Source that will signal that mySource completed
val sourceWithCompleteItem: Source[Either[Unit, A], _] =
mySource.map(a => Right(a)) ++ Source.single(Left(()))
// use statefulMapConcat
sourceWithCompleteItem.statefulMapConcat { () =>
var remainingMap = myMap
{
case Right(a: A) =>
// mySource emitted another item -> remove entry of same id from remainingMap
remainingMap -= a.id
// ...and emit the item to downstream
Iterable(a)
case Left(_) =>
// mySource completed -> emit the remaining values from the map
remainingMap.values
}
}
}
def addValuesToExistingSource(
mySource: Source[A, _],
myMapFuture: Future[Map[Id, A]]
): Source[A, _] = {
Source
.future(myMapFuture)
.flatMapConcat(addValuesToExistingSource(mySource, _))
}
Obviously, this has the downside that nothing will be emitted before the future completes.
Approach two: accumulate a set of all ids that were emitted:
def addValuesToExistingSourceB(
mySource: Source[A, _],
myMapFuture: Future[Map[Id, A]]
): Source[A, _] = {
// map to Right and append a single Source that will signal that mySource completed
val sourceWithCompleteItem: Source[Either[Unit, A], _] =
mySource.map(a => Right(a)) ++ Source.single(Left(()))
// accumulator type for scan:
case class ScanAcc(
emittedIds: Set[Id] = Set.empty,
isCompleted: Boolean = false,
itemOpt: Option[A] = None
)
sourceWithCompleteItem
.scan(ScanAcc()) {
case (acc, Right(a)) =>
ScanAcc(acc.emittedIds + a.id, isCompleted = false, Some(a))
case (acc, Left(_)) =>
ScanAcc(acc.emittedIds, isCompleted = true, None)
}
.flatMapConcat { scanAcc =>
if (scanAcc.isCompleted) {
Source
.future(myMapFuture)
.mapConcat(map => (map -- scanAcc.emittedIds).values)
} else {
scanAcc.itemOpt.fold[Source[A, _]](Source.empty)(Source.single)
}
}
}
This would emit before the future completes, but the downside is that you have this set in memory (which could become a problem depending how many items your source emits).
Here's that code with runnable examples: https://scastie.scala-lang.org/T6fd1tseTVmjGhcQfvoL0A
Related
I often find myself needing to chain collects where I want to do multiple collects in a single traversal. I also would like to return a "remainder" for things that don't match any of the collects.
For example:
sealed trait Animal
case class Cat(name: String) extends Animal
case class Dog(name: String, age: Int) extends Animal
val animals: List[Animal] =
List(Cat("Bob"), Dog("Spot", 3), Cat("Sally"), Dog("Jim", 11))
// Normal way
val cats: List[Cat] = animals.collect { case c: Cat => c }
val dogAges: List[Int] = animals.collect { case Dog(_, age) => age }
val rem: List[Animal] = Nil // No easy way to create this without repeated code
This really isn't great, it requires multiple iterations and there is no reasonable way to calculate the remainder. I could write a very complicated fold to pull this off, but it would be really nasty.
Instead, I usually opt for mutation which is fairly similar to the logic you would have in a fold:
import scala.collection.mutable.ListBuffer
// Ugly, hide the mutation away
val (cats2, dogsAges2, rem2) = {
// Lose some benefits of type inference
val cs = ListBuffer[Cat]()
val da = ListBuffer[Int]()
val rem = ListBuffer[Animal]()
// Bad separation of concerns, I have to merge all of my functions
animals.foreach {
case c: Cat => cs += c
case Dog(_, age) => da += age
case other => rem += other
}
(cs.toList, da.toList, rem.toList)
}
I don't like this one bit, it has worse type inference and separation of concerns since I have to merge all of the various partial functions. It also requires lots of lines of code.
What I want, are some useful patterns, like a collect that returns the remainder (I grant that partitionMap new in 2.13 does this, but uglier). I also could use some form of pipe or map for operating on parts of tuples. Here are some made up utilities:
implicit class ListSyntax[A](xs: List[A]) {
import scala.collection.mutable.ListBuffer
// Collect and return remainder
// A specialized form of new 2.13 partitionMap
def collectR[B](pf: PartialFunction[A, B]): (List[B], List[A]) = {
val rem = new ListBuffer[A]()
val res = new ListBuffer[B]()
val f = pf.lift
for (elt <- xs) {
f(elt) match {
case Some(r) => res += r
case None => rem += elt
}
}
(res.toList, rem.toList)
}
}
implicit class Tuple2Syntax[A, B](x: Tuple2[A, B]){
def chainR[C](f: B => C): Tuple2[A, C] = x.copy(_2 = f(x._2))
}
Now, I can write this in a way that could be done in a single traversal (with a lazy datastructure) and yet follows functional, immutable practice:
// Relatively pretty, can imagine lazy forms using a single iteration
val (cats3, (dogAges3, rem3)) =
animals.collectR { case c: Cat => c }
.chainR(_.collectR { case Dog(_, age) => age })
My question is, are there patterns like this? It smells like the type of thing that would be in a library like Cats, FS2, or ZIO, but I am not sure what it might be called.
Scastie link of code examples: https://scastie.scala-lang.org/Egz78fnGR6KyqlUTNTv9DQ
I wanted to see just how "nasty" a fold() would be.
val (cats
,dogAges
,rem) = animals.foldRight((List.empty[Cat]
,List.empty[Int]
,List.empty[Animal])) {
case (c:Cat, (cs,ds,rs)) => (c::cs, ds, rs)
case (Dog(_,d),(cs,ds,rs)) => (cs, d::ds, rs)
case (r, (cs,ds,rs)) => (cs, ds, r::rs)
}
Eye of the beholder I suppose.
How about defining a couple utility classes to help you with this?
case class ListCollect[A](list: List[A]) {
def partialCollect[B](f: PartialFunction[A, B]): ChainCollect[List[B], A] = {
val (cs, rem) = list.partition(f.isDefinedAt)
new ChainCollect((cs.map(f), rem))
}
}
case class ChainCollect[A, B](tuple: (A, List[B])) {
def partialCollect[C](f: PartialFunction[B, C]): ChainCollect[(A, List[C]), B] = {
val (cs, rem) = tuple._2.partition(f.isDefinedAt)
ChainCollect(((tuple._1, cs.map(f)), rem))
}
}
ListCollect is just meant to start the chain, and ChainCollect takes the previous remainder (the second element of the tuple) and tries to apply a PartialFunction to it, creating a new ChainCollect object. I'm not particularly fond of the nested tuples this produces, but you may be able to make it look a bit better if you use Shapeless's HLists.
val ((cats, dogs), rem) = ListCollect(animals)
.partialCollect { case c: Cat => c }
.partialCollect { case Dog(_, age) => age }
.tuple
Scastie
Dotty's *: type makes this a bit easier:
opaque type ChainResult[Prev <: Tuple, Rem] = (Prev, List[Rem])
extension [P <: Tuple, R, N](chainRes: ChainResult[P, R]) {
def partialCollect(f: PartialFunction[R, N]): ChainResult[List[N] *: P, R] = {
val (cs, rem) = chainRes._2.partition(f.isDefinedAt)
(cs.map(f) *: chainRes._1, rem)
}
}
This does end up in the output being reversed, but it doesn't have that ugly nesting from my previous approach:
val ((owls, dogs, cats), rem) = (EmptyTuple, animals)
.partialCollect { case c: Cat => c }
.partialCollect { case Dog(_, age) => age }
.partialCollect { case Owl(wisdom) => wisdom }
/* more animals */
case class Owl(wisdom: Double) extends Animal
case class Fly(isAnimal: Boolean) extends Animal
val animals: List[Animal] =
List(Cat("Bob"), Dog("Spot", 3), Cat("Sally"), Dog("Jim", 11), Owl(200), Fly(false))
Scastie
And if you still don't like that, you can always define a few more helper methods to reverse the tuple, add the extension on a List without requiring an EmptyTuple to begin with, etc.
//Add this to the ChainResult extension
def end: Reverse[List[R] *: P] = {
def revHelp[A <: Tuple, R <: Tuple](acc: A, rest: R): RevHelp[A, R] =
rest match {
case EmptyTuple => acc.asInstanceOf[RevHelp[A, R]]
case h *: t => revHelp(h *: acc, t).asInstanceOf[RevHelp[A, R]]
}
revHelp(EmptyTuple, chainRes._2 *: chainRes._1)
}
//Helpful types for safety
type Reverse[T <: Tuple] = RevHelp[EmptyTuple, T]
type RevHelp[A <: Tuple, R <: Tuple] <: Tuple = R match {
case EmptyTuple => A
case h *: t => RevHelp[h *: A, t]
}
And now you can do this:
val (cats, dogs, owls, rem) = (EmptyTuple, animals)
.partialCollect { case c: Cat => c }
.partialCollect { case Dog(_, age) => age }
.partialCollect { case Owl(wisdom) => wisdom }
.end
Scastie
Since you mentioned cats, I would also add solution using foldMap:
sealed trait Animal
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal
case class Snake(name: String) extends Animal
val animals: List[Animal] = List(Cat("Bob"), Dog("Spot"), Cat("Sally"), Dog("Jim"), Snake("Billy"))
val map = animals.foldMap{ //Map(other -> List(Snake(Billy)), cats -> List(Cat(Bob), Cat(Sally)), dogs -> List(Dog(Spot), Dog(Jim)))
case d: Dog => Map("dogs" -> List(d))
case c: Cat => Map("cats" -> List(c))
case o => Map("other" -> List(o))
}
val tuples = animals.foldMap{ //(List(Dog(Spot), Dog(Jim)),List(Cat(Bob), Cat(Sally)),List(Snake(Billy)))
case d: Dog => (List(d), Nil, Nil)
case c: Cat => (Nil, List(c), Nil)
case o => (Nil, Nil, List(o))
}
Arguably it's more succinct than fold version, but it has to combine partial results using monoids, so it won't be as performant.
This code is dividing a list into three sets, so the natural way to do this is to use partition twice:
val (cats, notCat) = animals.partitionMap{
case c: Cat => Left(c)
case x => Right(x)
}
val (dogAges, rem) = notCat.partitionMap {
case Dog(_, age) => Left(age)
case x => Right(x)
}
A helper method can simplify this
def partitionCollect[T, U](list: List[T])(pf: PartialFunction[T, U]): (List[U], List[T]) =
list.partitionMap {
case t if pf.isDefinedAt(t) => Left(pf(t))
case x => Right(x)
}
val (cats, notCat) = partitionCollect(animals) { case c: Cat => c }
val (dogAges, rem) = partitionCollect(notCat) { case Dog(_, age) => age }
This is clearly extensible to more categories, with the slight irritation of having to invent temporary variable names (which could be overcome by explicit n-way partition methods)
Imagine I have OptionT[IO, Value] like this
case class FailureMsg(code: String, ex: Option[Throwable])
val fff: IO[Either[FailureMsg, Int]] = OptionT.some[IO](12345)
.map { value ⇒
println("Mapping over")
value
}
.flatMapF[Int](_ ⇒ IO.raiseError(new RuntimeException("err1")))
.toRight(FailureMsg("Code0", None))
.recoverWith {
case ex ⇒ // Not Throwable!
EitherT.leftT[IO, Int](FailureMsg("Code1", Some(ex)))
}
.value
How can I catch err1 and wrap it into Left[FailureMsg]. I expected recoverWith help me but surprisingly it's alias of mapLeft. What should I do ?
I wrote helper class to do this.
implicit class EitherTExt[F[_], A, B](val obj: EitherT[F, A, B]) {
def recoverThrowable(pf: PartialFunction[Throwable, Either[A, B]])(implicit A: ApplicativeError[F, Throwable]): EitherT[F, A, B] =
EitherT(obj.value.recover(pf))
}
Let me know if there is more elegant shorter way.
I would follow the types.
val start: OptionT[IO, Int] = OptionT.some[IO](12345)
val thenMap: OptionT[IO, Int] = start.map { value ⇒
println("Mapping over")
value
}
// here it will get off the rails
val thenFlatMapF: OptionT[IO, Int] =
thenMap.flatMapF[Int](_ ⇒ IO.raiseError(new RuntimeException("err1")))
val thenToRight: EitherT[IO, FailureMsg, Int] =
thenFlatMapF.toRight(FailureMsg("Code0", None))
val result: IO[Either[FailureMsg, Int]] = thenToRight.value
thenFlatMapF won't produce OptionT[IO, Int] if IO.raiseError is the case, because no default mapping of Throwable to what? And you will get exception in folding result of IO.raiseError.
First attempt to fix it, will illustrate it:
val thenFlatMapF: OptionT[IO, Int] = thenMap.flatMapF[Int](_ ⇒ {
IO.raiseError[Option[Int]](new RuntimeException("err1")).recoverWith {
case err =>
val result: Option[Int] = ???
IO.pure(result)
}
})
How to handle error in place without breaking IO and return Option so that OptionT[IO, Int] is produced?
So basically, in this case, if you expect flatMapF to fail and need information on error, then it is better to have EitherT as its container, rather than OptionT.
Once done, possible solution shows that at some point leftMap or variance should be done to map the Throwable to FailureMsg. One of reasons is because IO has default error expressed as Throwable. One can't just mix FailureMsg and Throwable. Either inheritance is required so that FailureMsg is of type Throwable/Exception, or mapping should be done of errors in suitable places.
My rough solution would be:
val fff: IO[Either[FailureMsg, Int]] = OptionT.some[IO](12345)
// ok, let's do some input interpretation
.map { value ⇒
println("Mapping over")
value
}
// if no input, means error
.toRight(FailureMsg("Code0", None))
// if there is interpreted input to process, do it and map the errors
.flatMapF(_ ⇒ IO.raiseError[Int](new RuntimeException("err1")).attempt.map(_.leftMap {
case err: RuntimeException if err.getMessage == "err1" => FailureMsg("err1", Some(err))
// just for illustration, that if you have temptation to map on error,
// most likely there won't be only exception
case t: Throwable => FailureMsg("unexpected", Some(t))
}))
.value
However, normally contents of flatMapF would be a separate function or effect that would include error handling. Something like this:
val doJob: Int => IO[Either[FailureMsg, Int]] = arg =>
IO.raiseError[Int](new RuntimeException("err1")).attempt.map(_.leftMap {
case err: RuntimeException if err.getMessage == "err1" => FailureMsg("err1", Some(err))
case t: Throwable => FailureMsg("unexpected", Some(t))
})
val fff: IO[Either[FailureMsg, Int]] = OptionT.some[IO](12345)
.map { value ⇒
println("Mapping over")
value
}
.toRight(FailureMsg("Code0", None))
.flatMapF(arg ⇒ doJob(arg))
.value
I want to apply a sequence of transformations to a String but stopping when there is an error. This is an example of a more general pattern (a kind of Chain of Responsibility pattern or Visitor pattern)
If it is possible, I want to avoid using Cats or Scalaz at the moment. If you know how to do it on plain Scala and also Cats/Scalaz I will happy to see the code in the answer ;)
So following is my approach (assertions at the end of the code), but It is not stopping when an error is found. Basically is skipping the execution of the transformation X times.
type Error = String
sealed trait Transformer {
def transform(txt:String) : Either[Error, String]
}
object Transformer1 extends Transformer {
override def transform(txt: String): Either[Error, String] = Right(s"${txt}_One")
}
object Transformer2 extends Transformer {
override def transform(txt: String): Either[Error, String] = Right(s"${txt}_Two")
}
object Transformer3 extends Transformer {
override def transform(txt: String): Either[Error, String] = Right(s"${txt}_Three")
}
object TransformerError extends Transformer {
override def transform(txt: String): Either[Error, String] = Left("Error!!!!")
}
def transform(txt: String, transformers: Seq[Transformer]): Either[Error, String] =
transformers.foldLeft(Right(txt):Either[Error, String])( (result, t) => result match {
case Right(txt) => t.transform(txt)
case error => error
} )
val tOk = Seq(Transformer1, Transformer2, Transformer3)
val tError = Seq(Transformer1, TransformerError, Transformer3)
assert(transform("Whatever", tOk) == Right("Whatever_One_Two_Three"))
assert(transform("Whatever", tError) == Left("Error!!!!"))
Any suggestion?
Thanks!!
In Scala 2.12, Either is right-biased, so for-yield would do the trick.
for {
v1 <- Transformer1.transform("Whatever")
v2 <- Transformer2.transform(v1)
v3 <- Transformer3.transform(v2)
} yield {
v3
}
evaluates to Right(Whatever_One_Two_Three), while
for {
v1 <- Transformer1.transform("Whatever")
v2 <- TransformerError.transform(v1)
v3 <- Transformer3.transform(v2)
} yield {
v3
}
evaluates to Left(Error!!!!)
However, if you would like to return a result with all the transformations applied until an error was reached, that is,
assert(transform("Whatever", tError) == Right("Whatever_One"))
then the following refactoring of transform function might work:
def transform(txt: String, transformers: Seq[Transformer]): Either[Error, String] = {
type Current = Either[Error, String]
type Previous = Either[Error, String]
def foldLeftWithEarlyReturn: Tuple2[Current, Previous] = {
transformers.foldLeft[Tuple2[Current, Previous]](Right(txt) , Right(txt)){
(result, t) => result match {
case ( Right(txt) , Right(previousTxt) ) => ( t.transform(txt) , Right(txt) )
case ( Left(error) , Right(previousTxt) ) => return ( Right(previousTxt), Left(error) )
case e => e
}
}
}
if (foldLeftWithEarlyReturn._1.isLeft)
foldLeftWithEarlyReturn._2 // this means last transformation in sequence resulted in Left, so return previous
else
foldLeftWithEarlyReturn._1
}
When processing a collection, if you want early termination you often have to turn to recursion.
def transform(txt :String
,transformers :Seq[Transformer]
): Either[Error, String] = transformers match {
case Seq() => Right(txt)
case hd +: tl => hd.transform(txt).fold(Left(_), transform(_, tl))
}
A tail-recursive version is also possible, if a little less concise.
#tailrec
def transform(txt :String
,transformers :Seq[Transformer]
): Either[Error, String] = transformers match {
case Seq() => Right(txt)
case hd +: tl =>
val rslt = hd.transform(txt)
if (rslt.isLeft) rslt else transform(rslt.toSeq.head, tl)
}
Pure Scala
Probably, the simplest way to make your code short-circuiting, is to use return statement. It returns the result from the innermost named function it's contained in:
def transform(txt: String, transformers: Seq[Transformer]): Either[Error, String] =
transformers.foldLeft(Right(txt):Either[Error, String])( (result, t) =>
result match {
case Right(txt) => t.transform(txt)
case error => return error
} )
So the return error statement in this code would immediately return the first Left encountered from the transform function.
Cats
In cats you don't really have to do anything special. It short-circuits certain calls for some monads automatically, because monads have to implement tailRecM, and some monads (including Either) implement it in a lazy way to avoid doing useless flatMaps.
import cats.implicits._
def transformCats(txt: String, transformers: List[Transformer]): Either[Error, String] = {
// It seems this is needed to help Scala with type inference.
type Result[T] = Either[Error, T]
// foldLeftM is implemented in terms of tailRecM,
// and thus is short-circuiting for Either
transformers.foldLeftM(txt)((result, tf) => tf.transform(result): Result[String])
}
I have a sequence of instances where each instance can be implicitly converted to the same type.
What is the best way to convert such sequence?
class A
class B
trait Resolver {
def resolve: String
}
implicit class AResolver(a: A) extends Resolver {
def resolve: String = "a"
}
implicit class BResolver(b: B) extends Resolver {
def resolve: String = "b"
}
def resolveThem(a: Option[A], b: Option[B]): Iterable[String] = {
val resolvers: Seq[Resolver] = a ++ b // type error
val resolvers: Seq[Resolver] = List(a, b).collect{case Some(x: Resolver) => x} // empty
val resolvers: Seq[Resolver] = List(a, b).collect{case Some(x: A) => x} // unexpectedly for me but it is also type error when there is an x:A
val resolvers: Seq[Resolver] = List(a, b).collect{case Some(x: A) => x:Resolver} // works but returns only A as resolver
val resolvers: Seq[Resolver] = List(a, b).collect{case Some(x /*something that can be implicitly converted to Resolver*/) => x:Resolver} // Is it possible?
val resolvers: Seq[Resolver] = List(a.get, b.get) // this bad approach works
resolvers.map(_.resolve) // this is what I want as result
a.map(_.resolve) ++ b.map(_.resolve) // there is another way but if I have more arguments it becomes too long
}
You can only use implicits when exact type is available to compiler. As soon as you put your objects into a simple List their individual types disappear. (You could use HList though.)
For two arguments you just use your working approach.
For more arguments you might want to have a builder with one argument.
trait Builder {
def add[A: Resolver](a: A): Builder = {
use(a.resolve)
this
}
}
If there are only a few classes, you could use runtime match:
def getResolver(any: Any): Resolver = any match {
case a: A => a: Resolver
case b: B => b: Resolver
case _ => throw new IllegalArgumentException(s"$any is not supported"
}
However, this approach is very very bad. It is not extensible.
You could also use type classes instead of implicit conversions.
trait Resolvable[T] {
def resolve(a: T): String
}
implicit class AResolvable extends Resolvable[A] {
def resolve(a: A): String = "a"
}
This is the preferred way, I guess.
Method collect accepts PartialFunction[A, B], which means that function is defined only on a subset of the possible input arguments A and implicit conversions would not be applied.
Conversion should be done either explicitly or beforehand. One way of doing this for your case is a method taking varargs or a sequence:
def resolveThem (resolvers: Option[Resolver]*): Iterable[String] = {
resolvers.flatten.map(_.resolve)
}
resolveThem(Option(new A), Option(new B))
I have an idea (vague), to pass (or chain) some implicit value in this manner, not introducing parameters to block f:
def block(x: Int)(f: => Unit)(implicit v: Int) = {
implicit val nv = v + x
f
}
def fun(implicit v: Int) = println(v)
such that if I used something alike:
implicit val ii: Int = 0
block(1) {
block(2) {
fun
}
}
It would print 3.
If I could say def block(x: Int)(f: implicit Int => Unit).
In other words I'm seeking for some design pattern which will allow me to implement this DSL: access some cumulative value inside nested blocks but without explicitly passing it as parameter. Is it possible? (implicits are not necessary, just a hint to emphasize that I don't want to pass that accumulator explicitly). Of course upper code will print 0.
EDIT: One of possible usages: composing http routes, in a following manner
prefix("path") {
prefix("subpath") {
post("action1") { (req, res) => do action }
get("action2") { (req, res) => do action }
}
}
Here post and get will access (how?) accumulated prefix, say List("path", "subpath") or "/path/subpath/".
Consider using DynamicVariable for this. It's really simple to use, and thread-safe:
val acc: DynamicVariable[Int] = new DynamicVariable(0)
def block(x: Int)(f: => Unit) = {
acc.withValue(acc.value + x)(f)
}
def fun = println(acc.value)
Passing state via implicit is dirty and will lead to unexpected and hard to track down bugs. What you're asking to do is build a function that can compose in such a way that nested calls accumulate over some operation and anything else uses that value to execute the function?
case class StateAccum[S](init: S){
val op: S => S
def flatMap[A <: S](f: S => StateAccum[A]) ={
val StateAccum(out) = f(s)
StateAccum(op(init, out))
}
def apply(f: S => A) = f(init)
}
which could allow you do exactly what you're after with a slight change in how you're calling it.
Now, if you really want the nested control structures, your apply would have to use an implicit value to distinguish the types of the return such that it applied the function to one and a flatMap to StateAccum returns. It gets crazy but looks like the following:
def apply[A](f: S => A)(implicit mapper: Mapper[S, A]): mapper.Out = mapper(this, f)
trait Mapper[S, A]{
type Out
def apply(s: StateAccum[S], f: S => A): Out
}
object Mapper extends LowPriorityMapper{
implicit def acuum[S, A <: S] = new Mapper[S, StateAccum[A]]{
type Out = StateAccum[A]
def apply(s: StateAccum[S], f: S => StateAccum[A]) = s.flatMap(f)
}
}
trait LowPriorityMapper{
implicit def acuum[S, A] = new Mapper[S, A]{
type Out = A
def apply(s: StateAccum[S], f: S => A) = f(s.init)
}
}