Suppose I have a few nested functors, e.g. List[Option[Int]] and need to call the map of the most inner one.
Now I am using nested maps:
scala> val opts: List[Option[Int]] = List(Some(0), Some(1))
opts: List[Option[Int]] = List(Some(0), Some(1))
scala> opts.map(o => o.map(_ + 1))
res0: List[Option[Int]] = List(Some(1), Some(2))
What if I have 3 nesting levels, for instance ?
Is there any simple alternative to nested maps ?
Yes, this is possible with scalaz.Functor:
scala> import scalaz.Functor
import scalaz.Functor
scala> import scalaz.std.list._
import scalaz.std.list._
scala> import scalaz.std.option._
import scalaz.std.option._
scala> Functor[List].compose[Option].map(List(some(0), some(1)))(_ + 1)
res1: List[Option[Int]] = List(Some(1), Some(2))
However, this is longer than to simply call map with a nested map. If you often map nested structures, you can create helper functions:
def map2[F[_], G[_], A, B](fg: F[G[A]])(f: A => B)
(implicit F0: Functor[F], G0: Functor[G]): F[G[B]] =
F0.map(fg)(g => G0.map(g)(f))
def map3[F[_], G[_], H[_], A, B](fg: F[G[H[A]]])(f: A => B)
(implicit F0: Functor[F], G0: Functor[G], H0: Functor[H]): F[G[H[B]]] =
F0.map(fg)(g => G0.map(g)(h => H0.map(h)(f)))
...
Usage:
scala> map2(List(some(0), some(1)))(_ + 1)
res3: List[Option[Int]] = List(Some(1), Some(2))
scala> map3(List(some(some(0)), some(some(1))))(_ + 1)
res4: List[Option[Option[Int]]] = List(Some(Some(1)), Some(Some(2)))
If you have a lot of nested functors and you don't want to flatten them (i.e. they're not monads or you don't want to use them as monads) - then lenses may help. There is quicklens implementation, which supports traversable lenses : http://www.warski.org/blog/2015/03/quicklens-traversing-options-and-lists/.
Example (sorry didn't try to compile it):
modify(opts)(_.each.each).using(_ + 1)
Anyway, you have to specify nesting level, but you don't have to nest functions here. And it's enough to specify it once, like (conceptual example, didn't check):
def md2[T]: (l: List[Option[T]]) => modify(l)(_.each.each)
md2[Int](opts).using(_ + 1)
From the question I understood that you are tying to prune the list iterator e.i. remove upper levels of list in that case you can use flatten which convert list of lists into a single list.
I will be removing few layers of list using flatten
Code:-
val lists = List(
List(
List(
List("1"),List("2")
),
List(
List("3"),List("4")
) ,
List(
List("a"),List("b")
),
List(
List("c"),List("d")
)
)
)
val innerVal = lists.flatten.foreach(println)
results :-
List(List(1), List(2))
List(List(3), List(4))
List(List(a), List(b))
List(List(c), List(d))
Related
I have this:
Set[ValidatedNel[String, Double]]
and I would like to sum the Doubles in it to get:
ValidatedNel[String, Double]
If some elements in the values are then I would like to have matching strings.
I played with Set.sum and Numeric to no avail...
Here is the test of what I would like to achieve:
test("Summing ValidatedNel works") {
val val1: ValidatedNel[String, Double] = Valid(1.0)
val val2: ValidatedNel[String, Double] = Valid(2.0)
val values: Set[ValidatedNel[String, Double]] = Set(val1, val2)
val validatedNelNumeric: Numeric[ValidatedNel[String, Double]] = ???
val sum = values.sum(validatedNelNumeric)
assert(sum == Valid(3.0))
}
I don't manage to create the validatedNelNumeric...
To start with: it feels a little weird to use a set in this case (for a collection of Validated[..., Double] values). What part of the Set semantics do you care about? The unorderedness? Uniqueness?
In general the most straightforward way to sum up elements that have a Monoid instance is to use the combineAll method for things with a Foldable instance—for example a List (but not Set).
import cats.data.{ Validated, ValidatedNel }
import cats.instances.double._, cats.instances.list._
import cats.syntax.foldable._
// or just import cats.implicits._
val val1: ValidatedNel[String, Double] = Validated.valid(1.0)
val val2: ValidatedNel[String, Double] = Validated.valid(2.0)
val bad1: ValidatedNel[String, Double] = Validated.invalidNel("foo")
val bad2: ValidatedNel[String, Double] = Validated.invalidNel("bar")
val values = Set(val1, val2)
val withSomeBadOnes = Set(val1, bad1, val2, bad2)
And then:
scala> values.toList.combineAll
res0: cats.data.ValidatedNel[String,Double] = Valid(3.0)
scala> withSomeBadOnes.toList.combineAll
res1: cats.data.ValidatedNel[String,Double] = Invalid(NonEmptyList(foo, bar))
I'm guessing that's what you mean by "If some elements in the values are then I would like to have matching strings"?
You could also use SortedSet, since Cats provides a Foldable instance for SortedSet, but it's not as convenient:
scala> import cats.implicits._
import cats.implicits._
scala> import scala.collection.immutable.SortedSet
import scala.collection.immutable.SortedSet
scala> (SortedSet.empty[ValidatedNel[String, Double]] ++ values).combineAll
res2: cats.data.ValidatedNel[String,Double] = Valid(3.0)
scala> (SortedSet.empty[ValidatedNel[String, Double]] ++ withSomeBadOnes).combineAll
res3: cats.data.ValidatedNel[String,Double] = Invalid(NonEmptyList(bar, foo))
You could also use the standard fold and the |+| operator for monoids:
scala> values.fold(Validated.valid(0.0))(_ |+| _)
res4: cats.data.ValidatedNel[String,Double] = Valid(3.0)
To sum up: you can't call combineAll directly on your Set, since Cats doesn't provide a Foldable for Set. I'd suggest carefully reconsidering your use of the Set in any case, but if you decide to stick with it, you have a few options: convert to List or SortedSet like I have above, use the standard fold on Set, or finally write your own Foldable[Set] or use the one from alleycats.
I want to iterate over a list[List[String]] to subset it into a list[String] and then store each list from the list of lists in a val. The val's name could be anything but it should include each list index in its name.
For example:
val x: List[ List[String]] = List(List("Nike","Apple"), List("James", "Mike"))
Desired output:
group_0 : List[String] = List(Nike, Apple)
group_1 = List[String] = List(James, Mike)
Use zipWithIndex and convert into Map[String, List[String]]. Each key will be of form group_0, group_1 etc
val map = x.zipWithIndex.map(x => s"group_${x._2}" -> x._1).toMap
Access each list using key
map("group_0")
Scala REPL
scala> x.zipWithIndex.map(x => s"group_${x._2}" -> x._1).toMap
res4: scala.collection.immutable.Map[String,List[String]] = Map(group_0 -> List(Nike, Apple), group_1 -> List(James, Mike))
scala> res4("group_0")
res6: List[String] = List(Nike, Apple)
scala> res4("group_1")
res7: List[String] = List(James, Mike)
#Manoj Kumar Dhakd idea to use toMap is better
use function zipWithIndex and zip index with your lists then use map and create a Map
val listMap=x.zipWithIndex.map(grp=>"group_"+grp._2.toString->grp._1).toMap
Display your output like below
listMap.foreach(x=>println(x._1+"="+x._2))
//output:
group_0=List(Nike, Apple)
group_1=List(James, Mike)
x.zipWithIndex.foreach{case (x,y)=>println("group_"+y+": List[String] = "+x)}
Then, in Scala REPL:
scala> val x: List[ List[String]] = List(List("Nike","Apple"), List("James", "Mike"))
x: List[List[String]] = List(List(Nike, Apple), List(James, Mike))
scala> x.zipWithIndex.foreach{case (x,y)=>println("group_"+y+": List[String] = "+x)}
group_0: List[String] = List(Nike, Apple)
group_1: List[String] = List(James, Mike)
This is a follow-up to an answer to my previous question.
We know that functors compose. I can write a composition of functors List[_] and Option[_] using scalaz like this:
import scalaz._, Scalaz._
scala> val flist = Functor[List]
flist: scalaz.Functor[List] = scalaz.std.ListInstances$$anon$1#a5f0295
scala> val foption = Functor[Option]
foption: scalaz.Functor[Option] = scalaz.std.OptionInstances$$anon$1#51e43ad4
scala> flist compose foption
res0: scalaz.Functor[[α]List[Option[α]]] = scalaz.Functor$$anon$1#94c02b
scala> val f = flist compose foption
f: scalaz.Functor[[α]List[Option[α]]] = scalaz.Functor$$anon$1#610bffa0
scala> val os: List[Option[Int]] = Some(1) :: Some(2) :: None :: Nil
os: List[Option[Int]] = List(Some(1), Some(2), None)
scala> f.map(os) {_ + 1}
res1: List[Option[Int]] = List(Some(2), Some(3), None)
Is it the correct way to compose functors with scalaz ?
Could you give a real-life example of a functors composition ?
Suppose that you have a list of strings, where each string is a list of characters. By composing the two list functors, you get one functor over lists of strings. You can now map functions on characters, like, say, toUpper or toLower, to the list of strings.
Is this example realistic enough?:-)
For example,
Vector(Some(1), Some(2), Some(3), None).flatMap{
n => n
}
produces a Vector(1, 2, 3) instead of giving an error. As I have seen in other languages, flatMap is used when you have a mapper function that produces nesting so I would expect this to be a valid flatMap:
Vector(1, 2, 3).flatMap{
eachNum => Vector(eachNum)
}
My mapper function produces a Vector which would cause nesting (i.e. Vector(Vector(1), Vector(2), Vector(3), Vector(4))) if I used a map due to the container wrapping. However, flatMap will remove this nesting and flatten it. This makes sense when there is nesting of two identical monads.
However, I do not understand how using a flatMap with a mapper function that returns an Option makes a Vector[Option[Int]] become a Vector[Int]. Is there some sort of transformation going on (I have never seen this before), could someone explain and perhaps point me to some resources?
Thank you very much
we can use reify to see what is going on:
scala> import reflect.runtime.universe._
import reflect.runtime.universe._
scala> val v = Vector(Some(1), Some(2), Some(3), None)
v: scala.collection.immutable.Vector[Option[Int]] = Vector(Some(1), Some(2), Some(3), None)
scala> reify { v.flatMap(x => x) }
res0: reflect.runtime.universe.Expr[scala.collection.immutable.Vector[Int]] =
Expr[scala.collection.immutable.Vector[Int]]($read.v.flatMap(((x) =>
Option.option2Iterable(x)))(Vector.canBuildFrom))
This is showing us that it is using the option2Iterable conversion to convert the Option to Iterable, and Iterable is a subtype of the GenTraversableOnce type that flatMap is expecting.
The function f passed within the flatMap here:
Vector(Some(1), Some(2), Some(3), None).flatMap{
n => n
}
Is a function A => GenTraversableOnce[B] as described in the flatMap implementation:
def flatMap[B, That](f : scala.Function1[A, GenTraversableOnce[B]])
(implicit bf : CanBuildFrom[Repr, B, That])
: That = ???
The function implemented in your example n => n is:
(n: Option[Int]) => n
Where A is Option[Int] and B is Int.
Because CanBuildFrom is defined as trait CanBuildFrom[-From, -Elem, +To]:
From is Repr, and in this case Vector
Elem is B so Int
The result of flatMap is therefore Vector[Int]
Having
(Some(1), Some(2))
I expect to get
Some((1, 2))
and having
(Some(1), None)
I expect to get
None
I realize you're asking about Scalaz, but it's worth pointing out that the standard method is not unbearably wordy:
val x = (Some(1), Some(2))
for (a <- x._1; b <-x._2) yield (a,b)
In the general case (e.g. arbitrary-arity tuples), Shapeless is best at this sort of thing.
You can use the fact that Scalaz 7 provides a Bitraverse instance for tuples and then sequence as usual (but with bisequence instead of sequence):
scala> import scalaz._, std.option._, std.tuple._, syntax.bitraverse._
import scalaz._
import std.option._
import std.tuple._
import syntax.bitraverse._
scala> val p: (Option[Int], Option[String]) = (Some(1), Some("a"))
p: (Option[Int], Option[String]) = (Some(1),Some(a))
scala> p.bisequence[Option, Int, String]
res0: Option[(Int, String)] = Some((1,a))
Unfortunately Scalaz 7 currently needs the type annotation here.
In a comment Yo Eight states that the type annotation will remain mandatory here. I'm not sure what his or her reasoning is, but it's in fact perfectly easy to write your own wrapper that will provide any appropriately typed tuple with a bisequence method and won't require a type annotation:
import scalaz._, std.option._, std.tuple._
class BisequenceWrapper[F[_, _]: Bitraverse, G[_]: Applicative, A, B](
v: F[G[A], G[B]]
) {
def bisequence = implicitly[Bitraverse[F]].bisequence(v)
}
implicit def bisequenceWrap[F[_, _]: Bitraverse, G[_]: Applicative, A, B](
v: F[G[A], G[B]]
) = new BisequenceWrapper(v)
Now (some(1), some("a")).bisequence will compile just fine.
I can't think of a good reason Scalaz wouldn't include something like this. Whether or not you want to add it in the meantime is a matter of taste, but there's definitely no theoretical obstacle to letting the compiler do the typing here.
I think that cats version will not be redundant here.
# import cats.implicits._
import cats.implicits._
# (4.some, 2.some).bisequence
res1: Option[(Int, Int)] = Some((4, 2))
# (4.some, none).bisequence
res2: Option[Tuple2[Int, Nothing]] = None
Starting Scala 2.13, this exact behavior is provided in the standard library by Option#zip:
Some(2) zip Some('b') // Some((2, 'b'))
Some(2) zip None // None
None zip Some('b') // None
None zip None // None
Before Scala 2.13, Option#zip was returning an Iterable and it was possible to combine it with headOption:
Some(2) zip Some('b') headOption // Some((2, 'b'))
Some(2) zip None headOption // None
scala> import scalaz._
import scalaz._
scala> import Scalaz._
import Scalaz._
scala> (Tuple2.apply[Int, Int] _).lift[Option].tupled
res5: (Option[Int], Option[Int]) => Option[(Int, Int)] = <function1>
scala> res5((some(3), some(11)))
res6: Option[(Int, Int)] = Some((3,11))
scala> res5((some(3), none))
res7: Option[(Int, Int)] = None