Related
The goal is to lazily evaluate a collection of functions stopping on and returning the first happy result. Computation should be sequential. Here is my attempt
def f1(i: Int): Either[String, Int] = {println(s"f1($i)"); Left("boom-f1") }
def f2(i: Int): Either[String, Int] = {println(s"f2($i)"); Left("boom-f2") }
def f3(i: Int): Either[String, Int] = {println(s"f3($i)"); Right(i) }
val in = 42
(f1(in) #:: f2(in) #:: f3(in) #:: Stream.empty) collectFirst { case Right(x) => x } toRight("boom")
which outputs
f1(42)
f2(42)
f3(42)
res0: Either[String,Int] = Right(42)
where we see all three executed, whilst
def f1(i: Int): Either[String, Int] = {println(s"f1($i)"); Right(i) }
def f2(i: Int): Either[String, Int] = {println(s"f2($i)"); Right(i) }
def f3(i: Int): Either[String, Int] = {println(s"f3($i)"); Right(i) }
would output
f1(42)
res0: Either[String,Int] = Right(42)
where we see only one executed.
Does cats provide abstraction for such lazy failure-biased traversal?
You can use the Ior data type which is an inclusive-or relationship between two data types.
import cats.data.Ior
import cats.implicits._
import scala.annotation.tailrec
object Main2 {
def main(args: Array[String]) : Unit = {
def f1(i: Int): Either[String, Int] = {println(s"f1($i)"); Left("boom-f1") }
def f2(i: Int): Either[String, Int] = {println(s"f2($i)"); Left("boom-f2") }
def f3(i: Int): Either[String, Int] = {println(s"f3($i)"); Right(i) }
def traverseLazy(input: Int, list: List[Int => Either[String, Int]]): Ior[List[String], Int] = {
#tailrec
def go(ls: List[Int => Either[String, Int]], acc: List[String]): Ior[List[String], Int] = ls match {
case x :: xs => x(input) match {
case Left(error) => go(xs, error :: acc)
case Right(value) => if (ls.isEmpty) value.rightIor else Ior.both(acc, value)
}
case Nil => acc.leftIor
}
go(list, List.empty)
}
val res = traverseLazy(42, List(f1, f2, f3)).fold(
_.intercalate("\n"),
res => s"succeeded with $res",
(errors, res) => s"completed successfully with res $res but some errors were also found: ${errors.intercalate(", ")}")
println(res)
}
}
Ah I was overcomplicating, orElse already implements such semantics and gives simply
f1(in) orElse f2(in) orElse f3(in) orElse Left("boom")
as it takes by-name parameter.
I have the following function:
def function(i: Int): IO[Either[String, Option[Int]]] = ???
I want a function of the form:
def foo(either: Either[String, Option[Int]]): IO[Either[String, Option[Int]]]
and I want it to have the following behavior:
def foo1(either: Either[String, Option[Int]])
: IO[Either[String, Option[Int]]] = either match {
case Right(Some(i)) => bar(i)
case Right(None) => IO.pure(None.asRight)
case Left(s) => IO.pure(s.asLeft)
}
I want to do it less explicitly, so I tried EitherT:
def foo2(either: Either[String, Option[Int]]):
IO[Either[String, Option[Int]]] = {
val eitherT = for {
maybe <- EitherT.fromEither[IO](either)
int <- EitherT.fromOption(maybe, "???")
x <- EitherT(bar(int))
} yield x
eitherT.value
}
but this means that Right(None) will be mapped to IO(Left("???")) which is not what I want.
is there an alternative formulation with EitherT without a match expression that is equivalent to the foo1 implementation?
more importantly, how would an implementation that uses map/traverse/biTraverse/etc. (and doesn't match on any of option/eithers) look like?
p.s. The intention here is to define a "map" function for the following type:
trait Lookup[F[_], K, A] {
def get(key: K): F[Either[FormatError, Option[A]]]
}
without match
import cats._
import cats.data._
import cats.implicits._
def bar[F[_] : Applicative](i: Int): F[Either[String, Option[Int]]] =
(i + 1).some.asRight[String].pure[F]
def foo[F[_] : Applicative : Monad : FlatMap](either: Either[String, Option[Int]]): F[Either[String, Option[Int]]] =
OptionT(EitherT(either.pure[F])).flatMap { i =>
OptionT(EitherT(bar[F](i)))
}.value.value
foo[Id](1.some.asRight)
//res0: cats.Id[Either[String,Option[Int]]] = Right(Some(2))
import cats.Applicative
import cats.syntax.applicative._
def bar[F[_]](i: Int): F[Either[String, Option[Int]]] = ???
def foo[F[_] : Applicative](either: Either[String, Option[Int]]): F[Either[String, Option[Int]]] =
either match {
case Right(Some(i)) => bar(i)
case a => a.pure[F]
}
With MonadError we can:
eliminate 1 transformer during business logic implementation, so only OptionT is needed in def foo
do not make decision upfront how we want to handle errors, so user should choose concrete EitherT:
import cats._
import cats.data._
import cats.implicits._
import monix.eval._
type ErrorHandler[F[_]] = MonadError[F, String]
def bar[F[_] : ErrorHandler : Applicative](i: Int): F[Option[Int]] =
if (i > 0) (i + 1).some.pure[F] else implicitly[ErrorHandler[F]].raiseError("error")
def foo[F[_] : ErrorHandler : Applicative : FlatMap](option: Option[Int]): F[Option[Int]] =
OptionT(option.pure[F]).flatMap { i =>
OptionT(bar[F](i))
}.value
type Effect[A] = EitherT[Task, String, A]
import monix.execution.Scheduler.Implicits.global
foo[Effect](1.some).value.runSyncUnsafe()
//Either[String, Option[Int]] = Right(Some(2))
foo[Effect](0.some).value.runSyncUnsafe()
//Either[String, Option[Int]] = Left("error")
foo[Effect](none).value.runSyncUnsafe()
//Right(None)
I have a map which is something like
val m = Map("foo" -> "bar", "faz" -> "baz")
I need to write a custom get method, so that the key can be the key in the map with a number in the end.
So for example:
m.get("foo1") should return "bar"
I am looking for a good scala pattern to solve this problem.
Also I am generating the above map from a for loop using yield, so I can't do something like this
val m = CustomMap("foo" -> "bar")
Any solutions will be appreciated.
Thanks
First of all, you can generate a map from a for comprehension, and then convert it to CustomMap. You just need to define a
def apply(map: Map[String, String]) = CustomMap(map.toSeq :_*) in CustomMap - then you can do val m = CustomMap( for { ... } yield ... )
Secondly, if it doesn't have to be named get (it probably shouldn't be anyway), you can do this sort of thing with an implicit:
object PimpMyMap {
val pref = ".*?(\\d+)".r
implicit class Pimped[V](val map: Map[String,V]) extends AnyVal {
def getPrefix(key: String): Option[V] = map.get(key).orElse { key match {
case pref(k) => map.get(k)
case _ => None
}
}
Now you can write things like:
import PimpMyMap._
val map = Map("foo" -> 1)
val one = map.getPrefix("foo123") // Some(1)
val anotherOne = map.getPrefix("foo") // also Some(1);
You can do this with an implicit class and implicit conversion:
import scala.language.implicitConversions
object MapHelpers {
implicit def optionStringToString(maybeS: Option[String]): String = maybeS.getOrElse("")
implicit class MapWithIntKey(val m: Map[String, String]) extends Map[String, String] {
override def get(key: String): Option[String] = {
val intRegex = """(\d+)""".r
val keyWithoutInt = intRegex
.findFirstMatchIn(key)
.map(int => {
val idx = key.indexOf(int.toString)
key.slice(0, idx)
})
.getOrElse(key)
m.get(keyWithoutInt)
}
def +[V1 >: String](
kv: (String, V1)): scala.collection.immutable.Map[String, V1] = m + kv
def -(key: String): scala.collection.immutable.Map[String, String] = m - key
def iterator: Iterator[(String, String)] = m.iterator
}
}
object App {
import MapHelpers._
def testMapImplicit(): Unit = {
val myMap: MapWithIntKey = Map("foo" -> "bar", "faz" -> "baz")
val result: String = myMap.get("foo1")
println("result", result) // bar
}
}
Working Scastie
If you have a sure way to get the real key from the fake key, you can do this with Map.withDefault:
class CustomMap[K, +V] private (underlying: Map[K, Option[V]]) {
def get(k: K): Option[V] = underlying(k)
}
object CustomMap {
def apply[K, V](original: Map[K, V], keyReducer: K => K) = new CustomMap(originalMap.
mapValues(Some(_)).
withDefault(k => originalMap.get(keyReducer(k))
)
}
In your case, you can use this with
val stringKeyReducer: String => String = k.reverse.dropWhile(_.isDigit).reverse
to drop the digits at the end of your strings, so
CustomMap(Map("foo" -> "bar"), stringKeyReducer).get("foo1") = Some("bar")
Here is solution which combines both the answers.
import scala.language.implicitConversions
object MapHelpers {
implicit def optionStringToString(maybeS: Option[String]): String = maybeS.getOrElse("")
implicit class MapWithIntKey(val m: Map[String, String]) extends Map[String, String] {
override def get(key: String): Option[String] = {
val prefix = "(.*?)\\d+".r
m.get(key).orElse{
key match {
case prefix(p) => m.get(p)
case _ => None
}
}
}
def +[V1 >: String](kv: (String, V1)): scala.collection.immutable.Map[String, V1] = m + kv
def -(key: String): scala.collection.immutable.Map[String, String] = m - key
def iterator: Iterator[(String, String)] = m.iterator
}
}
object App {
import MapHelpers._
def testMapImplicit(): Unit = {
val myMap: MapWithIntKey = Map("foo" -> "bar", "faz" -> "baz")
println("result - number match ", myMap.get("foo1"))
println("result - exact match ", myMap.get("foo"))
}
}
App.testMapImplicit()
Working Scastie
The ordering of implicit seems to matter when using shapeless.
Look at the example code below where it will not work.
import shapeless._
case class Userz(i: Int, j: String, k: Option[Boolean])
object r {
def func(): Userz = {
val a = Userz(100, "UserA", Some(false))
val b = Userz(400, "UserB", None)
val genA = Generic[Userz].to(a)
val genB = Generic[Userz].to(b)
val genC = genA zip genB
val genD = genC.map(Mergerz)
val User = Generic[Userz].from(genD)
return User
}
}
object Mergerz extends Poly1 {
implicit def caseInt = at[(Int, Int)] {a => a._1 + a._2}
implicit def caseString = at[(String, String)] {a => a._1 + a._2}
implicit def caseBoolean = at[(Option[Boolean], Option[Boolean])] {a => Some(a._1.getOrElse(a._2.getOrElse(false)))}
}
r.func()
And the code below which will work
import shapeless._
case class Userz(i: Int, j: String, k: Option[Boolean])
object Mergerz extends Poly1 {
implicit def caseInt = at[(Int, Int)] {a => a._1 + a._2}
implicit def caseString = at[(String, String)] {a => a._1 + a._2}
implicit def caseBoolean = at[(Option[Boolean], Option[Boolean])] {a => Some(a._1.getOrElse(a._2.getOrElse(false)))}
}
object r {
def func(): Userz = {
val a = Userz(100, "UserA", Some(false))
val b = Userz(400, "UserB", None)
val genA = Generic[Userz].to(a)
val genB = Generic[Userz].to(b)
val genC = genA zip genB
val genD = genC.map(Mergerz)
val User = Generic[Userz].from(genD)
return User
}
}
r.func()
My question is, why does the order matters? I already tried importing the implicits which doesn't work.
Because type inference within a file basically works top-to-bottom. When it's typechecking func, it hasn't gotten to caseInt etc and doesn't know they are suitable. Annotating their types should work as well, and is generally recommended for implicits, but it may be problematic when using a library like Shapeless: see Shapeless not finding implicits in test, but can in REPL for an example.
The following code succeeds, but is there a better way of doing the same thing? Perhaps something specific to case classes? In the following code, for each field of type String in my simple case class, the code goes through my list of instances of that case class and finds the length of the longest string of that field.
case class CrmContractorRow(
id: Long,
bankCharges: String,
overTime: String,
name$id: Long,
mgmtFee: String,
contractDetails$id: Long,
email: String,
copyOfVisa: String)
object Go {
def main(args: Array[String]) {
val a = CrmContractorRow(1,"1","1",4444,"1",1,"1","1")
val b = CrmContractorRow(22,"22","22",22,"55555",22,"nine long","22")
val c = CrmContractorRow(333,"333","333",333,"333",333,"333","333")
val rows = List(a,b,c)
c.getClass.getDeclaredFields.filter(p => p.getType == classOf[String]).foreach{f =>
f.setAccessible(true)
println(f.getName + ": " + rows.map(row => f.get(row).asInstanceOf[String]).maxBy(_.length))
}
}
}
Result:
bankCharges: 3
overTime: 3
mgmtFee: 5
email: 9
copyOfVisa: 3
If you want to do this kind of thing with Shapeless, I'd strongly suggest defining a custom type class that handles the complicated part and allows you to keep that stuff separate from the rest of your logic.
In this case it sounds like the tricky part of what you're specifically trying to do is getting the mapping from field names to string lengths for all of the String members of a case class. Here's a type class that does that:
import shapeless._, shapeless.labelled.FieldType
trait StringFieldLengths[A] { def apply(a: A): Map[String, Int] }
object StringFieldLengths extends LowPriorityStringFieldLengths {
implicit val hnilInstance: StringFieldLengths[HNil] =
new StringFieldLengths[HNil] {
def apply(a: HNil): Map[String, Int] = Map.empty
}
implicit def caseClassInstance[A, R <: HList](implicit
gen: LabelledGeneric.Aux[A, R],
sfl: StringFieldLengths[R]
): StringFieldLengths[A] = new StringFieldLengths[A] {
def apply(a: A): Map[String, Int] = sfl(gen.to(a))
}
implicit def hconsStringInstance[K <: Symbol, T <: HList](implicit
sfl: StringFieldLengths[T],
key: Witness.Aux[K]
): StringFieldLengths[FieldType[K, String] :: T] =
new StringFieldLengths[FieldType[K, String] :: T] {
def apply(a: FieldType[K, String] :: T): Map[String, Int] =
sfl(a.tail).updated(key.value.name, a.head.length)
}
}
sealed class LowPriorityStringFieldLengths {
implicit def hconsInstance[K, V, T <: HList](implicit
sfl: StringFieldLengths[T]
): StringFieldLengths[FieldType[K, V] :: T] =
new StringFieldLengths[FieldType[K, V] :: T] {
def apply(a: FieldType[K, V] :: T): Map[String, Int] = sfl(a.tail)
}
}
This looks complex, but once you start working with Shapeless a bit you learn to write this kind of thing in your sleep.
Now you can write the logic of your operation in a relatively straightforward way:
def maxStringLengths[A: StringFieldLengths](as: List[A]): Map[String, Int] =
as.map(implicitly[StringFieldLengths[A]].apply).foldLeft(
Map.empty[String, Int]
) {
case (x, y) => x.foldLeft(y) {
case (acc, (k, v)) =>
acc.updated(k, acc.get(k).fold(v)(accV => math.max(accV, v)))
}
}
And then (given rows as defined in the question):
scala> maxStringLengths(rows).foreach(println)
(bankCharges,3)
(overTime,3)
(mgmtFee,5)
(email,9)
(copyOfVisa,3)
This will work for absolutely any case class.
If this is a one-off thing, you might as well use runtime reflection, or you could use the Poly1 approach in Giovanni Caporaletti's answer—it's less generic and it mixes up the different parts of the solution in a way I don't prefer, but it should work just fine. If this is something you're doing a lot of, though, I'd suggest the approach I've given here.
If you want to use shapeless to get the string fields of a case class and avoid reflection you can do something like this:
import shapeless._
import labelled._
trait lowerPriorityfilterStrings extends Poly2 {
implicit def default[A] = at[Vector[(String, String)], A] { case (acc, _) => acc }
}
object filterStrings extends lowerPriorityfilterStrings {
implicit def caseString[K <: Symbol](implicit w: Witness.Aux[K]) = at[Vector[(String, String)], FieldType[K, String]] {
case (acc, x) => acc :+ (w.value.name -> x)
}
}
val gen = LabelledGeneric[CrmContractorRow]
val a = CrmContractorRow(1,"1","1",4444,"1",1,"1","1")
val b = CrmContractorRow(22,"22","22",22,"55555",22,"nine long","22")
val c = CrmContractorRow(333,"333","333",333,"333",333,"333","333")
val rows = List(a,b,c)
val result = rows
// get for each element a Vector of (fieldName -> stringField) pairs for the string fields
.map(r => gen.to(r).foldLeft(Vector[(String, String)]())(filterStrings))
// get the maximum for each "column"
.reduceLeft((best, row) => best.zip(row).map {
case (kv1#(_, v1), (_, v2)) if v1.length > v2.length => kv1
case (_, kv2) => kv2
})
result foreach { case (k, v) => println(s"$k: $v") }
You probably want to use Scala reflection:
import scala.reflect.runtime.universe._
val rm = runtimeMirror(getClass.getClassLoader)
val instanceMirrors = rows map rm.reflect
typeOf[CrmContractorRow].members collect {
case m: MethodSymbol if m.isCaseAccessor && m.returnType =:= typeOf[String] =>
val maxValue = instanceMirrors map (_.reflectField(m).get.asInstanceOf[String]) maxBy (_.length)
println(s"${m.name}: $maxValue")
}
So that you can avoid issues with cases like:
case class CrmContractorRow(id: Long, bankCharges: String, overTime: String, name$id: Long, mgmtFee: String, contractDetails$id: Long, email: String, copyOfVisa: String) {
val unwantedVal = "jdjd"
}
Cheers
I have refactored your code to something more reuseable:
import scala.reflect.ClassTag
case class CrmContractorRow(
id: Long,
bankCharges: String,
overTime: String,
name$id: Long,
mgmtFee: String,
contractDetails$id: Long,
email: String,
copyOfVisa: String)
object Go{
def main(args: Array[String]) {
val a = CrmContractorRow(1,"1","1",4444,"1",1,"1","1")
val b = CrmContractorRow(22,"22","22",22,"55555",22,"nine long","22")
val c = CrmContractorRow(333,"333","333",333,"333",333,"333","333")
val rows = List(a,b,c)
val initEmptyColumns = List.fill(a.productArity)(List())
def aggregateColumns[Tin:ClassTag,Tagg](rows: Iterable[Product], aggregate: Iterable[Tin] => Tagg) = {
val columnsWithMatchingType = (0 until rows.head.productArity).filter {
index => rows.head.productElement(index) match {case t: Tin => true; case _ => false}
}
def columnIterable(col: Int) = rows.map(_.productElement(col)).asInstanceOf[Iterable[Tin]]
columnsWithMatchingType.map(index => (index,aggregate(columnIterable(index))))
}
def extractCaseClassFieldNames[T: scala.reflect.ClassTag] = {
scala.reflect.classTag[T].runtimeClass.getDeclaredFields.filter(!_.isSynthetic).map(_.getName)
}
val agg = aggregateColumns[String,String] (rows,_.maxBy(_.length))
val fieldNames = extractCaseClassFieldNames[CrmContractorRow]
agg.map{case (index,value) => fieldNames(index) + ": "+ value}.foreach(println)
}
}
Using shapeless would get rid of the .asInstanceOf, but the essence would be the same. The main problem with the given code was that it was not re-usable since the aggregation logic was mixed with the reflection logic to get the field names.