Scala views -- non-strict vs. lazy - scala

I am trying to create a "lazy" map of objects (actually, they are actors, but I am asking my question with a more trivial example).
Scala views are, in a sense, lazy. But their laziness is really just non-strictness. That's to say, the values are effectively call-by-name, which is in turn to say that the values are evaluated, when required, by invoking a Function0 (a no-parameter function).
What I'm interested in is a collection that is evaluated lazily, but is evaluated only once. Here's the kind of thing I'm looking for:
val x = Map(1->2, 2->2).view
val y = x map {case (k,v) => (k,{println("Hello");v.toString})}
val z1 = y.find{case (k,_) => k==1}
val z2 = y.find{case (k,_) => k==1}
When I put this into a Scala worksheet, what I get is:
x: scala.collection.IterableView[(Int, Int),scala.collection.immutable.Map[Int,Int]] = IterableView(...)
y: scala.collection.IterableView[(Int, String),Iterable[_]] = IterableViewM(...)
Hello
z1: Option[(Int, String)] = Some((1,1))
Hello
z2: Option[(Int, String)] = Some((1,1))
Everything is just as it should be. Except that I don't want to see that second "Hello". In other words, I only want the mapped function (toString) to be invoked once -- when needed.
Does anyone have a suggestion of how to achieve my goal? It's not super-important but I'm curious if it can be done.

You can almost get what you want using a Stream:
scala> val x = TreeMap(1->2, 2->2) // to preserve order
x: scala.collection.immutable.TreeMap[Int,Int] = Map(1 -> 2, 2 -> 2)
scala> val y = x.toStream map {case (k,v) => (k,{println(s"Hello $k");v.toString})}
Hello 1
y: scala.collection.immutable.Stream[(Int, String)] = Stream((1,2), ?)
scala> y.find{case (k,_) => k==1}
res8: Option[(Int, String)] = Some((1,2))
scala> y.find{case (k,_) => k==2}
Hello 2
res9: Option[(Int, String)] = Some((2,2))
as you can see, the first element is evaluated strictly, but the others are evaluated and memoized on-demand
If you make the stream itself a lazy val, you get what you want:
scala> val x = TreeMap(1->2, 2->2) // to preserve order
x: scala.collection.immutable.TreeMap[Int,Int] = Map(1 -> 2, 2 -> 2)
scala> lazy val y = x.toStream map {case (k,v) => (k,{println(s"Hello $k");v.toString})}
y: scala.collection.immutable.Stream[(Int, String)] = <lazy>
scala> y.find{case (k,_) => k==1}
Hello 1
res10: Option[(Int, String)] = Some((1,2))
scala> y.find{case (k,_) => k==1}
res11: Option[(Int, String)] = Some((1,2))
If you don't mind evaluating the whole collection at once when you use it, you just need a lazy val and the collection can stay what it is (map, list etc)
val x = TreeMap(1->2, 2->2)
lazy val y = x map {case (k,v) => (k,{println(s"Hello $k");v.toString})}
I don't think you can have a (really) lazy map, but I'd be happy if someone proved me wrong :)
edit:
You can have a (sort of) lazy map by wrapping your values like this:
class Lazy[T](x: => T) {
lazy val value = x
override def toString = value.toString
}
object Lazy {
implicit def toStrict[T](l: Lazy[T]): T = l.value
}
val x = TreeMap(1->2, 2->2)
lazy val y = x map {case (k,v) => (k, new Lazy({println(s"Hello $k");v.toString}))}
y.find{case (k,v) => v.indexOf("x");k==1} // let's use v to evaluate it, otherwise nothing gets printed
y.find{case (k,v) => v.indexOf("x");k==1}
The implicit conversion allows you to use your values as if they were of their original type

I would propose alternative solution, instead of laziness.
What if your v will be function but not value.
In such case you'd be able to control execution whenever you need without relying on collections laziness...
val y = x map {case (k,v) => (k,() => {println("Hello");v.toString})}

I do not know of any collection API that offers that kind of laziness. However, I think you can achieve what you want with function memoization as described here:
case class Memo[I <% K, K, O](f: I => O) extends (I => O) {
import collection.mutable.{Map => Dict}
val cache = Dict.empty[K, O]
override def apply(x: I) = cache getOrElseUpdate (x, f(x))
}
val x = Map(1->2, 2->2).view
val memo = Memo { v: Int =>
println("Hello")
v.toString
}
val y = x.map { case (k, v) =>
(k, memo(v))
}
val z1 = y.find{case (k,_) => k==1}
val z2 = y.find{case (k,_) => k==1}
output:
Hello
z1: Option[(Int, String)] = Some((1,2))
z2: Option[(Int, String)] = Some((1,2))

Related

Composing functions that return an option

Suppose I have a few functions of type Int => Option[Int]:
def foo(n: Int): Int => Option[Int] = {x => if (x == n) none else x.some}
val f0 = foo(0)
val f1 = foo(1)
I can compose them with >=> as follows:
val composed: Int => Option[Int] = Kleisli(f0) >=> Kleisli(f1)
Suppose now I need to compose all functions from a list:
val fs: List[Int => Option[Int]] = List(0, 1, 2).map(n => foo(n))
I can do it with map and reduce:
val composed: Int => Option[Int] = fs.map(f => Kleisli(f)).reduce(_ >=> _)
Can it (the composed above) be simplified ?
If you want the composition monoid (as opposed to the "run each and sum the results" monoid), you'll have to use the Endomorphic wrapper:
import scalaz._, Scalaz._
val composed = fs.foldMap(Endomorphic.endoKleisli[Option, Int])
And then:
scala> composed.run(10)
res11: Option[Int] = Some(10)
The monoid for kleisli arrows only requires a monoid instance for the output type, while the composition monoid requires the input and output types to be the same, so it makes sense that the latter is only available via a wrapper.
[A] Kleisli[Option, A, A] is a Semigroup via Compose, so we can use foldMap1:
val composed: Int => Option[Int] = fs.foldMap1(f => Kleisli(f))
Interestingly this doesn't work, though if we pass the correct instance explicitly then it does:
scala> val gs = NonEmptyList(fs.head, fs.tail: _*)
gs: scalaz.NonEmptyList[Int => Option[Int]] = NonEmptyList(<function1>, <function1>, <function1>)
scala> gs.foldMap1(f => Kleisli(f))(Kleisli.kleisliCompose[Option].semigroup[Int])
res20: scalaz.Kleisli[Option,Int,Int] = Kleisli(<function1>)
scala> gs.foldMap1(f => Kleisli(f))(Kleisli.kleisliCompose[Option].semigroup[Int]).apply(1)
res21: Option[Int] = None
I'm not sure where the instance that seems to take priority is coming from.

Applicative instance for ZipList in Scala

This is a follow-up to one of my recent previous questions:
I would like to define a zip Applicative instance for List (and probably Set and Map). For example:
val xs: List[Int] = List(1, 2, 3)
val fs: List[Int => Int] = List(f1, f2, f3)
val ys: List[Int] = xs <*> fs // expected to be List(f1(1), f2(2), f3(3))
So I defined a ZipList and its Applicative:
case class ZipList[A](val list: List[A])
implicit val zipListApplicative = new Applicative[ZipList] {
def point[A](a: => A): ZipList[A] = ZipList(List(a))
def ap[A, B](za: => ZipList[A])(zf: => ZipList[A => B]): ZipList[B] = {
val bs = (za.list zip zf.list) map {case (a, f) => f(a)}
ZipList(bs)
}
}
and can use it as follows:
scala> val xs: List[Int] = List(1, 2, 3)
xs: List[Int] = List(1, 2, 3)
scala> val fs: List[Int => Int] = List(_ + 2, _ + 2, _ +1)
fs: List[Int => Int] = List(<function1>, <function1>, <function1>)
scala> ZipList(xs) <*> ZipList(fs)
res4: ZipList[Int] = ZipList(List(3, 4, 4))
It seems to be working but maybe I am missing something.
Does zipListApplicative comply to the applicative laws ?
Is ZipList supposed to be a stream because the point should generate an infinite stream of values ? Why ?
Applicatives should satisfy the law
point identity <*> v == v
which yours does not since
point identity List(1,2,3) == List(1)
pure a for a zip list should return an infinite stream of a which is why you need a lazy data structure.

How can I combine a tuple of values with a tuple of functions?

I have scalaZ available.
I have an (A, B) and a (A => C, B => D), I'd like to get a (C, D) in a simple and readable way.
I feel like there's something I can do with applicatives but I can't find the right methods.
Edit
Didn't get it at first, that the OP has tuple of functions. In such case as suggested in comments this should work:
val in = ("1", 2)
val fnT = ((s: String) => s.toInt, (i: Int) => i.toString)
val out = (in.bimap[Int, String] _).tupled(fnT)
Old
If you have two functions and want to apply them on tuple, you should be able to do:
import scalaz._
import Scalaz._
val in = ("1", 2)
val sToi = (s: String) => s.toInt
val iTos = (i: Int) => i.toString
val out = sToi <-: in :-> iTos
// or
val out1 = in.bimap(sToi, iTos)
// or
val out2 = (sToi *** iTos)(in)
Arrows? Something like:
(f *** g)(a, b)
http://eed3si9n.com/learning-scalaz/Arrow.html
I'm not finding scalaz more readable. Whats wrong with defining your own function.
def biFunc(valTup:(A,B), funTup:((A)=>C,(B)=>D)):(C,D) = (funTup._1(valTup._1), funTup._2(valTup._2))
I agree with Lionel Port, but you could make it more readable via:
case class BiFun[A,B,C,D](f1:A=>C, f2: B=>D){
def applyTo(a: (A,B)) = (f1(a._1), f2(a._2))
}
object BiFun{
implicit def toBiFun(a: (A=>C, B=>D)) = BiFun(a._1, a._2)
}
used like:
import BiFun._
val ab = (A(1), B(2))
val ac = (x: A) => C(x.i+2)
val bd = (x: B) => D(x.i+2)
val bifn = (ac, bd)
bifn applyTo ab
So, in the end you end up with funTuple applyTo tuple and gain your top level readability
Writing this method yourself might be the best bet:
def bimap[A,B,C,D](vals:(A, B), funcs:(A=>C, B=>D)):(C,D) = {
val ((func1, func2), (val1, val2)) = funcs -> vals
func1(val1) -> func2(val2)
}
And if you're doing this a lot, you might even enhance the tuple class:
implicit class EnhancedTuple2[A, B](val vals: (A, B)) extends AnyVal {
def bimap[C, D](funcs: (A=>C, B=>D)) = {
val ((func1, func2), (val1, val2)) = funcs -> vals
func1(val1) -> func2(val2)
}
}
So that you can do:
val func1: Int => Int = x => x * x
val func2: Int => String = x => x.toString
val tupledFuncs = func1 -> func2
(1, 2).bimap(tupledFuncs)

What's the idiomatic way to map producing 0 or 1 results per entry?

What's the idiomatic way to call map over a collection producing 0 or 1 result per entry?
Suppose I have:
val data = Array("A", "x:y", "d:e")
What I'd like as a result is:
val target = Array(("x", "y"), ("d", "e"))
(drop anything without a colon, split on colon and return tuples)
So in theory I think I want to do something like:
val attempt1 = data.map( arg => {
arg.split(":", 2) match {
case Array(l,r) => (l, r)
case _ => (None, None)
}
}).filter( _._1 != None )
What I'd like to do is avoid the need for the any-case and get rid of the filter.
I could do this by pre-filtering (but then I have to test the regex twice):
val attempt2 = data.filter( arg.contains(":") ).map( arg => {
val Array(l,r) = arg.split(":", 2)
(l,r)
})
Last, I could use Some/None and flatMap...which does get rid of the need to filter, but is it what most scala programmers would expect?
val attempt3 = data.flatMap( arg => {
arg.split(":", 2) match {
case Array(l,r) => Some((l,r))
case _ => None
}
})
It seems to me like there'd be an idiomatic way to do this in Scala, is there?
With a Regex extractor and collect :-)
scala> val R = "(.+):(.+)".r
R: scala.util.matching.Regex = (.+):(.+)
scala> Array("A", "x:y", "d:e") collect {
| case R(a, b) => (a, b)
| }
res0: Array[(String, String)] = Array((x,y), (d,e))
Edit:
If you want a map, you can do:
scala> val x: Map[String, String] = Array("A", "x:y", "d:e").collect { case R(a, b) => (a, b) }.toMap
x: Map[String,String] = Map(x -> y, d -> e)
If performance is a concern, you can use collection.breakOut as shown below to avoid creation of an intermediate array:
scala> val x: Map[String, String] = Array("A", "x:y", "d:e").collect { case R(a, b) => (a, b) } (collection.breakOut)
x: Map[String,String] = Map(x -> y, d -> e)

How do I find the min() or max() of two Option[Int]

How would you find minValue below?
I have my own solution but want to see how others would do it.
val i1: Option[Int] = ...
val i2: Option[Int] = ...
val defaultValue: Int = ...
val minValue = ?
Update: I just noticed that my solution below and the one in your answer behave differently—I read your question as asking for the minimum of the two values when there are two values, but in your answer you're effectively treating None as if it contained a value that's either bigger (for min) or smaller (for max) than anything else.
To be more concrete: if i1 is Some(1) and i2 is None, my solution will return the default value, while yours will return 1.
If you want the latter behavior, you can use the default semigroup instance for Option[A] and the tropical semigroup for Int. In Scalaz 7, for example, you'd write:
import scalaz._, Scalaz._
optionMonoid(Semigroup.minSemigroup[Int]).append(i1, i2) getOrElse defaultValue
Or the following shorthand:
Tags.Min(i1) |+| Tags.Min(i2) getOrElse defaultValue
It's not as clean as the applicative functor solution below, but if that's your problem, that's your problem.
Here's a more idiomatic way that doesn't involve creating an extra list:
(for { x <- i1; y <- i2 } yield math.min(x, y)) getOrElse defaultValue
Or, equivalently:
i1.flatMap(x => i2.map(math.min(x, _))) getOrElse defaultValue
What you're doing is "lifting" a two-place function (min) into an applicative functor (Option). Scalaz makes this easy with its applicative builder syntax:
import scalaz._, Scalaz._
(i1 |#| i2)(math.min) getOrElse defaultValue
The standard library solution isn't much less elegant in this case, but this is a useful abstraction to know about.
I solved a similar problem using the following approach. We handle a special case when both of the options have values, otherwise we use an API method Option.orElse.
val a: Option[Int] = Some(10)
val b: Option[Int] = Some(20)
val c: Option[Int] = (a, b) match {
case (Some(x), Some(y)) => Some(x min y)
case (x, y) => x orElse y
}
I think this is what you're after:
val minValue = List(i1, i2).flatten match {
case Nil => defaultValue
case xs => xs.min
}
I'd avoid sorted since sorting requires a lot more processing than simply finding the max or min (although it probably doesn't make much difference in this case).
val minValue: Int = List(i1, i2).flatten.sorted.headOption getOrElse defaultValue
You can use patterns in for expressions, values that do not match the pattern are discarded.
(for (Some(x) <- List(None, Some(3))) yield x) max
Not as good as the List.flatten approach though.
Another option which wasn't mentioned is using reduceLeftOption (interchange math.max and math.min as desired):
val min = (first ++ second).reduceLeftOption(math.min).getOrElse(defaultValue)
scala> val first = Some(10)
first: Some[Int] = Some(10)
scala> val second: Option[Int] = None
second: Option[Int] = None
scala> val defaultMin = -1
defaultMin: Int = -1
scala> (first ++ second).reduceLeftOption(math.min).getOrElse(defaultMin)
res7: Int = 10
scala> val first: Option[Int] = None
first: Option[Int] = None
scala> (first ++ second).reduceLeftOption(math.min).getOrElse(defaultMin)
res8: Int = -1
scala> val first = Some(10)
first: Some[Int] = Some(10)
scala> val second = Some(42)
second: Some[Int] = Some(42)
scala> (first ++ second).reduceLeftOption(math.min).getOrElse(defaultMin)
res9: Int = 10
We can combine the 2 Options as an Iterable with Option's ++ operator, which allows us to use minOption (to nicely handle the case of the empty iterable formed by the None/None case) and fallback on a default value if necessary with getOrElse:
(optionA ++ optionB).minOption.getOrElse(-1)
// None and None => -1
// Some(5) and None => 5
// None and Some(5) => 5
// Some(5) and Some(3) => 3
If you want to avoid using scalaz and map/for/getOrElse, you can do the following:
val minValue = (i1, i2) match {
case (Some(x), Some(y)) => math.min(x, y)
case _ => defaultValue
}
tl;dr
You can do that you need elegant using custom cats Semigroup instances:
import cats.kernel.Semigroup
import cats.instances.option._ // this import is for cats std option combiner
import cats.syntax.semigroup._
object Implicits {
implicit val intMinSemigroup: Semigroup[Int] =
(x: Int, y: Int) => math.min(x, y)
implicit val intMaxSemigroup: Semigroup[Int] =
(x: Int, y: Int) => math.max(x, y)
}
import Implicits.intMinSemigroup
// these are results for minSemigroup
// List((Some(1),Some(1),Some(2)), (Some(1),Some(1),None), (None,Some(2),Some(2)), (None,None,None))
//import Implicits.intMaxSemigroup
// these are results for maxSemigroup
// List((Some(1),Some(2),Some(2)), (Some(1),Some(1),None), (None,Some(2),Some(2)), (None,None,None))
for {
maybeA <- Seq(Some(1), None)
maybeB <- Seq(Some(2), None)
} yield (maybeA, maybeA |+| maybeB, maybeB)
if you want replace None by default value you can use combine twice:
val defaultValue: Int = 3
val optionMin = for {
maybeA <- Seq(Some(1), None)
maybeB <- Seq(Some(2), None)
} yield (maybeA |+| maybeB) |+| Some(defaultValue)
// List(Some(1), Some(1), Some(2), Some(3))
How it works
Shortly, Semigroup[A] is typeclass for combining two values of the same type A into the one value of type A.
Here we use std cats OptionMonoid (it extends Semigroup[Option[A]]) here source code:
class OptionMonoid[A](implicit A: Semigroup[A]) extends Monoid[Option[A]] {
def empty: Option[A] = None
def combine(x: Option[A], y: Option[A]): Option[A] =
x match {
case None => y
case Some(a) =>
y match {
case None => x
case Some(b) => Some(A.combine(a, b))
}
}
}
We see that it takes option matching on his own and everything what we should give him to work is implicit A: Semigroup[A]. In our case we write two different combiners for min, max cases:
object Implicits {
implicit val intMinSemigroup: Semigroup[Int] =
(x: Int, y: Int) => math.min(x, y)
implicit val intMaxSemigroup: Semigroup[Int] =
(x: Int, y: Int) => math.max(x, y)
}
So, we import combiners (i.e. import Implicits.intMinSemigroup) and just use cats.syntax.semigroup for using combine function as operator |+|:
maybeA |+| maybeB.
In conclusion, you can just define your custom semigroup for any type (not only Int) and combine options of this type after importing some cats syntax and instances.