Implement repository with State Monad (use IO and State together) - scala

I have this repository :
trait TrainRepository {
def get(trainId: TrainId): IO[Option[Train]]
def getAll: IO[List[Train]]
def save(train: Train): IO[Train]
}
I would like to provide an in-memory implementation using a State Monad.
But I am stuck :
if I extend the trait, I will be stuck with the types IO[...] so I believe that I would not be able to use a State Monad.
do I need to use a natural transformation?
do I need to use a Free Monad? (I would rather not)
How would you do that?
EDIT to give a little bit more context:
trait TrainRepository[F[_]] {
def get(trainId: TrainId): F[Option[Train]]
def save(train: Train): F[Train]
}
class TrainService[F[_]](repository: TrainRepository[F])(implicit monad: Monad[F]) {
def reservation(id: TrainId): F[Train] =
for{
train <- repository.get(id)
updatedTrain <- train match {
case None => monad.pure("test") // return error here
case Some(train) => monad.pure(train.bookSeat)
}
_ <- repository.save(updatedTrain)
} yield updatedTrain
}
type TrainStateRepository[A] = State[Map[TrainId, Train], A]
val inMemoryTrainRepository = new TrainRepository[TrainStateRepository] {
override def get(trainId: TrainId): TrainStateRepository[Option[Train]] = ???
override def save(train: Train): TrainStateRepository[Train] = ???
}
val postgresTrainRepository = new TrainRepository[IO] {
override def get(trainId: TrainId): IO[Option[Train]] = ???
override def save(train: Train): IO[Train] = ???
}
val testTrainService = new TrainService[IO](inMemoryTrainRepository)
// The error is here ^^^^
// I cannot mix IO and State
val prodTrainService = new TrainService[IO](postgresTrainRepository)

You can introduce a type parameter in order to abstract over your monad:
trait TrainRepository[F[_]] {
def get(trainId: TrainId): F[Option[Train]]
def getAll: F[List[Train]]
def save(train: Train): F[Train]
}
Then your implementation with state monad can look like
type TrainsState[A] = State[Map[TrainId, Train], A]
class StateTrainRepository extends TrainRepository[TrainsState] {
override def get(trainId: TrainId): TrainsState[Option[Train]] = State.inspect(_.get(trainId))
override def getAll: TrainsState[List[Train]] = State.inspect(_.values.toList)
override def save(train: Train): TrainsState[Train] =
State.modify[Map[TrainId, Train]](m => m + (train.id -> train)) *> State.pure(train)
}

Related

How to pattern match all classes with context bound

I have a type class and a few instances:
trait TC[T] { def doThings(x: T): Unit }
implicit val tcA = new TC[A] { /* ... */}
implicit val tcB = new TC[B] { /* ... */}
implicit val tcC = new TC[C] { /* ... */}
/* ... */
In my call site, I have input as Any, and I need to check if there is an implicit for the input actual type:
def process(in: Any) = in match {
case x: A => implicitly[TC[A]].doThings(x)
case x: B => implicitly[TC[B]].doThings(x)
case x: C => implicitly[TC[C]].doThings(x)
//...
}
This seems tedious and unnecessary, as I have to list all the classes that have this type class instance. Can I achieve this by something like:
def process(in: Any) = in match {
case x: T : TC => implicitly[TC[T]].doThings(x) //This does not work
}
Edit: input is an Any (an Object from a Java library). Cannot use generic or context bound on the input.
If you really want to do what you have mentioned in your question, you can write it as below, but if you just want to call doThings by finding an implicit instance of appropriate TC - refer João Guitana answer
object Main extends App {
class A
class B
class C
trait TC[T] { def doThings(x: T): Unit }
implicit val tcA = new TC[A] {
override def doThings(x: A): Unit = println("From A")
}
implicit val tcB = new TC[B] {
override def doThings(x: B): Unit = println("From B")
}
implicit val tcC = new TC[C] {
override def doThings(x: C): Unit = println("From C")
}
def process[T: ClassTag](in: T) = in match {
case x: A => implicitly[TC[A]].doThings(x)
case x: B => implicitly[TC[B]].doThings(x)
case x: C => implicitly[TC[C]].doThings(x)
}
process(new A())
process(new B())
process(new C())
}
/* === Output ====
From A
From B
From C
*/
You need to ask for an implicit TC, Any won't work. As follows:
trait TC[T] { def doThings(x: T): Unit }
implicit def tcS: TC[String] = new TC[String] {
override def doThings(x: String): Unit = println("string")
}
implicit def tcI: TC[Int] = new TC[Int] {
override def doThings(x: Int): Unit = println("int")
}
def process[T : TC](x: T): Unit = implicitly[TC[T]].doThings(x)
process("")
process(1)
// process(4L) wont compile
Try it out!

How to implement typesafe domain repository in scala?

I want to implement generic and typesafe domain repository. Say I have
trait Repo[Value] {
def put(value: Value): Unit
}
case class IntRepo extends Repo[Int] {
override def put(value: Int): Unit = ???
}
case class StringRepo extends Repo[String] {
override def put(value: String): Unit = ???
}
case class DomainRepo(intRepo: IntRepo, stringRepo: StringRepo) {
def putAll[?](values: ?*): Unit // what type should be here?
}
As result I want to have following api:
domainRepo.putAll(1, 2, 3, "foo", "bar") //Should work
domainRepo.putAll(1, 2, true, "foo") // should not compile because of boolean value
The question is How to achieve this?
so, I see only one way to make it typesafe. It's to do pattern matching on Any type like
def putAll(values: Seq[Any]) => Unit = values.foreach {
case str: String => stringRepo.put(str)
case int: Int => intRepo.put(int)
case _ => throw RuntimeException // Ha-Ha
}
but what if I would have 10000 of types here? it would be a mess!
another not clear for me approach for now is to use dotty type | (or) like following:
type T = Int | String | 10000 other types // wouldn't be a mess?
def putAll(t: T*)(implicit r1: Repo[Int], r2: Repo[String] ...) {
val myTargetRepo = implicitly[Repo[T]] // would not work
}
so, what do you think? is it even possible?
the easies way I've saw was
Map[Class[_], Repo[_]]
but this way allows to do a lot of errors
It seems you are looking for a type class
trait Repo[Value] {
def put(value: Value): Unit
}
implicit val intRepo: Repo[Int] = new Repo[Int] {
override def put(value: Int): Unit = ???
}
implicit val stringRepo: Repo[String] = new Repo[String] {
override def put(value: String): Unit = ???
}
case object DomainRepo {
def putAll[Value](value: Value)(implicit repo: Repo[Value]): Unit = repo.put(value)
}
If you want domainRepo.putAll(1, 2, 3, "foo", "bar") to compile and domainRepo.putAll(1, 2, true, "foo") not to compile, you can try to use heterogeneous collection (HList).
import shapeless.{HList, HNil, ::, Poly1}
import shapeless.ops.hlist.Mapper
trait Repo[Value] {
def put(value: Value): Unit
}
implicit val intRepo: Repo[Int] = new Repo[Int] {
override def put(value: Int): Unit = ???
}
implicit val stringRepo: Repo[String] = new Repo[String] {
override def put(value: String): Unit = ???
}
case object DomainRepo {
def put[Value](value: Value)(implicit repo: Repo[Value]): Unit = repo.put(value)
object putPoly extends Poly1 {
implicit def cse[Value: Repo]: Case.Aux[Value, Unit] = at(put(_))
}
def putAll[Values <: HList](values: Values)(implicit
mapper: Mapper[putPoly.type, Values]): Unit = mapper(values)
}
DomainRepo.putAll(1 :: 2 :: 3 :: "foo" :: "bar" :: HNil)
// DomainRepo.putAll(1 :: 2 :: true :: "foo" :: HNil) // doesn't compile

In Scala, how to deal with heterogeneous list of the same parameterized type

I have an array of Any (in real life, it's a Spark Row, but it's sufficient to isolate the problem)
object Row {
val buffer : Array[Any] = Array(42, 21, true)
}
And I want to apply some operations on its elements.
So, I've defined a simple ADT to define a compute operation on a type A
trait Op[A] {
def cast(a: Any) : A = a.asInstanceOf[A]
def compute(a: A) : A
}
case object Count extends Op[Int] {
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op[Boolean] {
override def compute(a: Boolean): Boolean = a
}
Given that I have a list of all operations and I know which operation is to apply to each element, let's use these operations.
object GenericsOp {
import Row._
val ops = Seq(Count, Exist)
def compute() = {
buffer(0) = ops(0).compute(ops(0).cast(buffer(0)))
buffer(1) = ops(0).compute(ops(0).cast(buffer(1)))
buffer(2) = ops(1).compute(ops(1).cast(buffer(2)))
}
}
By design, for a given op, types are aligned between cast and combine. But unfortunately the following code does not compile. The error is
Type mismatch, expected: _$1, actual: AnyVal
Is there a way to make it work ?
I've found a workaround by using abstract type member instead of type parameter.
object AbstractOp extends App {
import Row._
trait Op {
type A
def compute(a: A) : A
}
case object Count extends Op {
type A = Int
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op {
type A = Boolean
override def compute(a: Boolean): Boolean = a
}
val ops = Seq(Count, Exist)
def compute() = {
val op0 = ops(0)
val op1 = ops(1)
buffer(0) = ops(0).compute(buffer(0).asInstanceOf[op0.A])
buffer(1) = ops(0).compute(buffer(1).asInstanceOf[op0.A])
buffer(2) = ops(1).compute(buffer(2).asInstanceOf[op1.A])
}
}
Is there a better way ?
It seems that your code can be simplified by making Op[A] extend Any => A:
trait Op[A] extends (Any => A) {
def cast(a: Any) : A = a.asInstanceOf[A]
def compute(a: A) : A
def apply(a: Any): A = compute(cast(a))
}
case object Count extends Op[Int] {
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op[Boolean] {
override def compute(a: Boolean): Boolean = a
}
object AbstractOp {
val buffer: Array[Any] = Array(42, 21, true)
val ops: Array[Op[_]] = Array(Count, Count, Exist)
def main(args: Array[String]): Unit = {
for (i <- 0 until buffer.size) {
buffer(i) = ops(i)(buffer(i))
}
println(buffer.mkString("[", ",", "]"))
}
}
Since it's asInstanceOf everywhere anyway, it does not make the code any less safe than what you had previously.
Update
If you cannot change the Op interface, then invoking cast and compute is a bit more cumbersome, but still possible:
trait Op[A] {
def cast(a: Any) : A = a.asInstanceOf[A]
def compute(a: A) : A
}
case object Count extends Op[Int] {
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op[Boolean] {
override def compute(a: Boolean): Boolean = a
}
object AbstractOp {
val buffer: Array[Any] = Array(42, 21, true)
val ops: Array[Op[_]] = Array(Count, Count, Exist)
def main(args: Array[String]): Unit = {
for (i <- 0 until buffer.size) {
buffer(i) = ops(i) match {
case op: Op[t] => op.compute(op.cast(buffer(i)))
}
}
println(buffer.mkString("[", ",", "]"))
}
}
Note the ops(i) match { case op: Opt[t] => ... } part with a type-parameter in the pattern: this allows us to make sure that cast returns a t that is accepted by compute.
As a more general solution than Andrey Tyukin's, you can define the method outside Op, so it works even if Op can't be modified:
def apply[A](op: Op[A], x: Any) = op.compute(op.cast(x))
buffer(0) = apply(ops(0), buffer(0))

Combine two functions under the same name without overloading

Here is the code:
def transform1(f: String => String): Unit = {
val s = getString
f.andThen(putString)(s)
}
def transform2(f: String => Option[String]): Unit = {
val s = getString
f(s).foreach(putString(_))
}
How do you express these two ideas in one single function?
Method overloading does not work and seems discouraged by the community.
I didn't understand that why anyone may want this but here is a way to do it:
def transform(f: Either[(String => String), (String => Option[String])]: Unit = f match {
case Left(f) => // do transform1 here
case Right(f) => //do transform2 here
}
As I said at the begining you probably shouldn't want to do this; perhaps you should directly ask what you want.
The pattern to avoid overloading is to convert disparate arguments to a common, specific type. There could be any number of such conversions.
Not sure this is the most compelling example, however.
object X {
trait MapFlat[-A, +B] { def apply(x: A): B }
implicit class mapper[A](val f: A => A) extends MapFlat[A, A] {
override def apply(x: A) = {
val res = f(x)
println(res)
res
}
}
implicit class flatmapper[A](val f: A => Option[A]) extends MapFlat[A, Option[A]] {
override def apply(x: A) = {
val res = f(x)
res foreach println
res
}
}
def f[B](g: MapFlat[String, B]) = {
g("abc")
}
}
object Test extends App {
import X._
f((s: String) => s)
f((s: String) => Some(s))
}
One way to do it will be type classes, here's a sample -
trait Transformer[T] {
def transform(foo: String => T)
}
object Transformer {
implicit object StringTransformer extends Transformer[String] {
override def transform(foo: (String) => String): Unit = ??? // Your logic here
}
implicit object OptStringTransformer extends Transformer[Option[String]] {
override def transform(foo: (String) => Option[String]): Unit = ??? // Your logic here
}
}
class SampleClass {
def theOneTransformYouWant[T: Transformer](f: String => T) = {
implicitly[Transformer[T]].transform(f)
}
def canUseBothWays(): Unit = {
theOneTransformYouWant((s: String) => s)
theOneTransformYouWant((s: String) => Some(s))
}
}
Another way would be the magnet pattern
http://spray.io/blog/2012-12-13-the-magnet-pattern/
sealed trait TransformationMagnet {
def apply(): Unit
}
object TransformationMagnet {
implicit def fromString(f: String => String): TransformationMagnet =
new TransformationMagnet {
def apply(): Unit = ??? // Your code goes here
}
implicit def fromOptString(f: String => Option[String]): TransformationMagnet =
new TransformationMagnet {
def apply(): Unit = ??? // your code goes here
}
}
class SampleClass {
def theOneTransformYouWant(f: TransformationMagnet) = {
???
}
def hereWeUseItInBothWays(): Unit = {
theOneTransformYouWant((s: String) => s)
theOneTransformYouWant((s: String) => Some(s))
}
}
add a new parameter on the description typeOfTransform
add a conditional inside the function
if (typeOfTransform == type1){
//functionality1
}else {
//functionality2
}
Just for completeness, you can actually overload methods like this by adding implicit arguments which will always be available:
def transform(f: String => Option[String]): Unit = ...
def transform(f: String => String)(implicit d: DummyImplicit): Unit = ...

Can a Scala "extractor" use generics on unapply?

Can't I use a generic on the unapply method of an extractor along with an implicit "converter" to support a pattern match specific to the parameterised type?
I'd like to do this (Note the use of [T] on the unapply line),
trait StringDecoder[A] {
def fromString(string: String): Option[A]
}
object ExampleExtractor {
def unapply[T](a: String)(implicit evidence: StringDecoder[T]): Option[T] = {
evidence.fromString(a)
}
}
object Example extends App {
implicit val stringDecoder = new StringDecoder[String] {
def fromString(string: String): Option[String] = Some(string)
}
implicit val intDecoder = new StringDecoder[Int] {
def fromString(string: String): Option[Int] = Some(string.charAt(0).toInt)
}
val result = "hello" match {
case ExampleExtractor[String](x) => x // <- type hint barfs
}
println(result)
}
But I get the following compilation error
Error: (25, 10) not found: type ExampleExtractor
case ExampleExtractor[String] (x) => x
^
It works fine if I have only one implicit val in scope and drop the type hint (see below), but that defeats the object.
object Example extends App {
implicit val intDecoder = new StringDecoder[Int] {
def fromString(string: String): Option[Int] = Some(string.charAt(0).toInt)
}
val result = "hello" match {
case ExampleExtractor(x) => x
}
println(result)
}
A variant of your typed string decoder looks promising:
trait StringDecoder[A] {
def fromString(s: String): Option[A]
}
class ExampleExtractor[T](ev: StringDecoder[T]) {
def unapply(s: String) = ev.fromString(s)
}
object ExampleExtractor {
def apply[A](implicit ev: StringDecoder[A]) = new ExampleExtractor(ev)
}
then
implicit val intDecoder = new StringDecoder[Int] {
def fromString(s: String) = scala.util.Try {
Integer.parseInt(s)
}.toOption
}
val asInt = ExampleExtractor[Int]
val asInt(Nb) = "1111"
seems to produce what you're asking for. One problem remains: it seems that trying to
val ExampleExtractor[Int](nB) = "1111"
results in a compiler crash (at least inside my 2.10.3 SBT Scala console).