In Scala, how can I append an Option[A] to Option[A]:
Meaning:
Some("foo") ??? Some("bar") == Some("foobar")
In Haskell I'd use an applicative:
ghci>import Control.Applicative
ghci> (++) <$> (Just "foo") <*> (Just "bar")
Just "foobar"
Are there Applicatives in Scala's standard Typesafe library?
With scalaz you can do it this way:
import scalaz.syntax.applicative._
import scalaz.std.option._
val l: Option[String] = Some("foo")
val r: Option[String] = Some("bar")
val result = ^(l, r)(_ + _)
println(result) // Some("foobar")
Applicatives aren't in the standard library, but you can use for-comprehensions like monads in Haskell:
for {
l <- Some("foo")
r <- Some("bar")
} yield (l + r)
(or rewrite it with flatMap, of course). Otherwise, go with scalaz, as in Eugene's answer.
If you just want to achieve this particular syntax, you can combine an implicit class with a monad for-comprehension:
implicit class RichOption(a: Option[String]) {
def ???(b: Option[String]) = for (sa <- a; sb <- b) yield sa+sb
}
scala> Some("foo") ??? Some("bar") == Some("foobar")
res4: Boolean = true
Related
I have the following in my Scala
import scalaz.effect.IO
val i: Iterator[IO[List[String]]] = null
val ii: Iterator[IO[List[String]]] = for{ //This does not compile
io <- i;
lst <- io
} yield lst
Why? What's wrong?
I expected the ii is completely the same as i. But it refuses to compile:
Error:(12, 11) type mismatch;
found : scalaz.effect.IO[List[String]]
required: scala.collection.GenTraversableOnce[scalaz.effect.IO[List[String]]]
lst <- io
flatMap in scala
Recall that for-comprehensions are just sugared calls to flatMap:
for {
a <- expr //expr must return M[A] such that M has a
//flatMap method: flatMap[B](f: A => N[B]) for some N
b <- f(a) //f(a) must be an N[B]
...
Your question
Here is the signature of Iterator.flatMap
def flatMap[B](f: A => GenTraversableOnce[B]): Iterator[B]
But you were attempting to supply a function returning an IO[B]:
lst <- io //You cannot just have `io` on the right here
hence the compilation error.
flatMap in scala again
Scala's flatMap <~> for-comprehension conversions as they apply to collection types (and Option) are (in my opinion) confusing as they allow you to switch between different types of Monad (e.g. List/Option/Set etc). For example, what is the type of x here?
val x =
for {
i <- List(1, 2, 3)
j <- Option(i + 1)
k <- Stream(i, j)
} yield k
Monads in scalaz
Having a closer look at scalaz.Monad's flatMap:
trait Monad[M[_]] {
def flatMap[A, B](ma: M[A])(f: A => M[B]): M[B]
}
The type of M is always fixed. That is, in this comprehension:
lazy val ma: M[A] = ???
for (a <- ma; b <- f(a)) yield b
The result type of the function f must be in M[B] for some B. Whilst sometimes this can be a little irritating, it has the advantage of being completely predictable. You never get confused about what monad your for comprehension is in.
Back to the question
It is not obvious what you want, but here are a few suggestions:
i.toStream.sequence.map(flatten) //IO[Stream[String]]
i and io must be of the same monad:
io <- i // i is an Iterator[...]
lst <- io // io is an IO[List[String]]
When using IO and for-comprehensions, one option is to use .unsafeToFuture in your for comprehension. In your example, this would be:
val ii: Iterator[IO[List[String]]] = for{
io <- i;
lst <- io.unsafeToFuture()
} yield lst
I have this line of code, where I use the most idiomatic way I know, for destructuring an object coming back from a function:
val (a, b) = foo match { case MyObjectType(a, b) => (a, b) }
The object's prototype being:
case class MyObjectType(Type1: SomeType1, Type2: SomeType2)
Of course I could otherwise:
val returnType = foo
val (a, b) = (returnType.a, returnType.b)
But the latter is rather a different form of stating the same problem - this is really not elegant. Could a Scala macro come to the rescue to provide a succinct idiom? perhaps allowing syntax like either:
val (a, b) = foo deconstruct { MyObjectType(a, b) => (a, b) } // merely more shorthand, like scala allows e.g. within a map block
val (a, b) = tuplize(foo) // assumes tuplize can iterate the vals of MyObjectType
tupleResult(a, b) = foo // radical macro api exploring the limits of macro safety...
tupledVars(foo) // macro extreme
Kind of an answer, but that does not give you a tuple. Do you know that this works:
val MyObjectType(a,b) = foo
Also if you are destructuring varargs T* you can do Code such as follows:
val Array(first, second, _*) = Array(1,2,3,4)
val Array(fst, snd, _*) = Array(1,2)
If you want tuples directly see In Scala, is there an easy way to convert a case class into a tuple?
You may wish to explore generic programming with Shapeless
scala> import shapeless._, syntax.std.product._, syntax.std.tuple._
import shapeless._
import syntax.std.product._
import syntax.std.tuple._
scala> case class Foo(i: Int, s: String, b: Boolean)
defined class Foo
scala> val foo = Foo(1, "foo", true)
foo: Foo = Foo(1,foo,true)
Now with the help of Generic we can convert Foo to HList and back
scala> Generic[Foo].to(foo)
res0: shapeless.::[Int,shapeless.::[String,shapeless.::[Boolean,shapeless.HNil]]] = 1 :: foo :: true :: HNil
scala> Generic[Foo].from(res0)
res1: Foo = Foo(1,foo,true)
Or you can use nice syntactic sugar provided by syntax.std.product
scala> foo.toHList
res2: this.Repr = 1 :: foo :: true :: HNil
scala> foo.toTuple
res3: (Int, String, Boolean) = (1,foo,true)
See feature overview and examples for more information.
So a very very common pattern in Scala is a for comprehension as follows:
for {
i <- monadA
j <- monadB
} yield (i, j)
Similarly for 3-tuples, ..., n-tuples. This is becoming so common in my code I'd imagine that scalaz provide some awesome operator to do this for me, e.g. monadA funnyOperator monadB funnyOperator monadC. I've looked around and can't seem to find anything. So I've defined my own implicit class for 2-tuples and 3-tuples but would prefer to use scalaz.
Bonus
In response the currently accepted answer, would love to see someone tell how to make this compile:
import scalaz.Scalaz._
// Like a 1 element list
case class MyMonad[+T](x: T) {
def map[U](f: T => U): MyMonad[U] = MyMonad(f(x))
def flatMap[U](f: T => MyMonad[U]): MyMonad[U] = f(x)
}
val myMonad: MyMonad[(Int, Int)] = (MyMonad(1) |#| MyMonad(2)).tupled
and not give:
error: value |#| is not a member of MyMonad[Int]
Bonus Solution:
You need to "provide an applicative instance" e.g.
implicit def myMonadApplicative: Bind[MyMonad] = new Bind[MyMonad] {
def bind[A, B](fa: MyMonad[A])(f: A => MyMonad[B]): MyMonad[B] = fa.flatMap(f)
def map[A, B](fa: MyMonad[A])(f: A => B): MyMonad[B] = fa.map(f)
}
Given that each Monad is an Applicative you can also use
(monadA |#| monadB).tupled
E.g.
scala> val b: List[(Int, Int)] = (List(1, 2, 3) |#| List(4, 6)).tupled
b: List[(Int, Int)] = List((1,4), (1,6), (2,4), (2,6), (3,4), (3,6))
You can use sequence; I can never remember whether you need shapeless-scalaz for this or not:
(monadA, monadB).sequence
(monadA, monadB, monadC).sequence
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.
suppose I have
type VS[A] = Validation[String, A]
val v: VS[Option[A]]
val f: A => VS[B]
I want to get a result of type VS[Option[B]] but if v is a Success(None), the result should also be a Success(None). Here's an example:
scala> val v: VS[Option[String]] = some("4.5").success
v: VS[Option[String]] = Success(Some(4.5))
scala> val f = (s : String) => (try { s.toInt.success } catch { case x => x.getMessage.fail }): VS[Int]
f: String => VS[Int] = <function1>
Then:
scala> import Validation.Monad._
import Validation.Monad._
scala> (v map2 f map (_.sequence)).join
res4: scalaz.Validation[String,Option[Int]] = Failure(For input string: "4.5")
The success case is:
scala> val v: VS[Option[String]]= some("5").success
v: VS[Option[String]] = Success(Some(5))
scala> (v map2 f map (_.sequence)).join //UGLY composition
res7: scalaz.Validation[String,Option[Int]] = Success(Some(5))
And the empty case is:
scala> val v: VS[Option[String]]= none[String].success
v: VS[Option[String]] = Success(None)
scala> (v map2 f map (_.sequence)).join
res6: scalaz.Validation[String,Option[Int]] = Success(None)
Is there a "nicer" way of doing this (possibly involving kleisli composition or monad transformers)?
The monad transformer OptionT does exactly what you want here, and its flatMapF method makes usage a clean one-liner.
I'm going to use Scalaz 7's disjunction type (\/) instead of Validation in this example, since the latter isn't a monad in Scalaz 7, but the principle is the same.
import scalaz._, std.option._, syntax.id._, syntax.monad._
type DS[+A] = String \/ A
type ODS[A] = OptionT[DS, A]
def f(s: String) = try s.toInt.right catch { case e => e.getMessage.left }
Now we can write the following:
scala> val v = OptionT(some("4.5").point[DS])
v: scalaz.OptionT[DS,java.lang.String] = OptionT(\/-(Some(4.5)))
scala> (v flatMapF f).run
res0: DS[Option[Int]] = -\/(For input string: "4.5")
Or equivalently:
scala> ("4.5".point[ODS] flatMapF f).run
res1: DS[Option[Int]] = -\/(For input string: "4.5")
Or the success case:
scala> ("4".point[ODS] flatMapF f).run
res2: DS[Option[Int]] = \/-(Some(4))
Or the empty case:
scala> (OptionT(none.point[DS]) flatMapF f).run
res3: DS[Option[Int]] = \/-(None)
As desired.