andThen
or similar on Validated
that does what you're looking for.
Parallel
construct.
@noelwelsh , here is a solution, I tried to apply to compose failfast with failslow:
import cats.syntax.either._
import cats.instances.list._ // for Semigroupal
def oneDateAfterAnotherFailSlow(dateBefore:String, dateAfter:String)
(map: Map[String, String])(format: SimpleDateFormat)
: FailFast[Tuple2[Date, Date]] =
for {
t <-Semigroupal[FailSlow].product(
readDate(dateBefore)(map)(format).toValidated,
readDate(dateAfter)(map)(format).toValidated
).toEither
r <- oneAfterAnother(t._1, t._2)
} yield r
Can you please comment it, how it looks, is it clear, is there a better approach?
Hi all,
A question with Readers.
Here is a simple service example, whose methods return reader:
trait Service1_1{
def s1f1:Reader[Map[String,Int],Int] =
Reader(_("name"))
def s1f2:Reader[Map[String,Int],Int] =
Reader(_("age"))
}
Here is a service-consumer, that accepts parameter, map, and also returns reader itself:
trait Service1_2 {
def s12f1(i:Int, map:Map[String,Int]):Reader[Service1_1, Int] =
Reader(s => {
val r = for {
r1 <- s.s1f1
r2 <- s.s1f2
} yield r1 + r2
r.run(map) + i
})
}
Ok, to use Service1_2.s12f1
I must have map in the parameter list:
object s1 extends Service1_1
object s2 extends Service1_2
val r = s2.s12f1(3, Map("age"-> 1, "name"-> 2)).run(s1)
The question: how to implement Service1_2.s12f2
:
trait Service1_2 {
def s2f2 = ???
}
In order to be able to run it like:
s2.s2f2(2)
.run(s1)
.run(Map("age"-> 1, "name"-> 2))
Cannot get it.
I could implement it:
def s2f2(i:Int): Reader[Service1_1, Reader[Map[String,Int],Int]] =
Reader(s => Reader(map => {
val r = for {
r1 <- s.s1f1
r2 <- s.s1f2
} yield r1 + r2
r.run(map) + i
}))
The question, is there a better approach? Or at least syntax? Cause with several levels of dependency, it will look strange.
Hi guys, theoretical question:
When we implement DI via Reader, we make a dependency a part of our method signature. Assume we have (without implementations):
trait Service1 { def f1:Int = ??? }
trait Service2 { def f2:Reader[Service1, Int] = ??? }
type Env= (Service1, Service2)
def c:Reader[Env, Int] = ??? //use Service2.f2 here
Now, f2
needs additional service for implementation, say:
trait Service3
type Service2Env = (Service1, Service3)
//new dependecies on both:
trait Service2 { def f2:Reader[Service2Env, Int] = ??? }
It will break existing clients, they cannot any longer to use Service2.f2
without providing Service3
additionally.
With DI via injection (via constructor or setters), which is common in OOP, I would use in a dependency only Service2
. How it is constructed and what is its list of dependencies, I do not care. From this point, any new dependencies in Service2
will keep the signature of c function unchanged.
How is it solved in FP? Are there options? Is there a way to inject new dependencies, but somehow protect customers from the change?
Hello there, I am reading the build.sbt
for Scala and looking at code like
publishArtifact in (Compile, packageDoc)
and
packageOptions in Compile in packageSrc
Do they both mean the same things as I read code? That is Compile:packageDoc::publishArtifact
and Compile:packageSrc::packageOptions
?
(1, "2", true)
it's really syntactic sugar for scala.Tuple3[Int, String, Boolean](1, "2", true)
Tuple1
, Tuple2
... and so on
case class Square(size: Double) extends Rectangular {
val height: Double = size
val width: Double = size
}
trait Rectangular extends Shape {
def height: Double
def width: Double
val sides: Int = 4
override val perimeter: Double = 2 * (height + width)
override val area: Double = height * width
}
trait Shape {
def sides: Int
def perimeter: Double
def area: Double
}
val square = Square(4)
println(square.height)
println(square.width)
println(square.size)
println(square.area)
println(square.perimeter)
println(square.sides)
4.0
4.0
4.0
0.0
0.0
4
perimeter
and area
should be defined with def
as methods rather than as vals
override def perimeter: Double = 2 * (height + width)
override def area: Double = height * width
Another way to do it is declare them lazy
. Then they will only be initialised upon first use
override lazy val perimeter: Double = 2 * (height + width)
override lazy val area: Double = height * width
Due to the immutability of the traits and classes, they will always be the correct value as neither height nor width will be subsequently updated.