How to lazy evaluate functions in a sequence in Scala - scala

Let's say I have three functions in a class that can return a Option[File]. I am looking for a nice way to execute them in order and stop when the first function evaluates to a Some (similar to what pick() does but with lazy evaluation), i.e. I don't want to use nested if-else statements.
abstract class Foo() {
def first(): Option[File]
def second(): Option[File]
def third(): Option[File]
def pick(): Option[File] = {
Seq(first(), second(), third()).find(_.isDefined).map(_.get)
)
}

The parameter to Option.orElse is passed by name, so you can just use that to chain your methods:
def pick(): Option[File] = first orElse second orElse third

scala> def f1:Option[Int] = {println("1"); None}
f1: Option[Int]
scala> def f2:Option[Int] = {println("2"); Some(2)}
f2: Option[Int]
scala> def f3:Option[Int] = {println("3"); Some(3)}
f3: Option[Int]
scala> f1 orElse f2 orElse f3
1
2
res0: Option[Int] = Some(2)

Related

no type parameters for method flatMap

I don't know why the following code can not compile, this is the error message:
Error:(29, 7) no type parameters for method flatMap: (f: String => Option[B])Option[B] exist so that it can be applied to arguments (String => Some[Class[?0]] forSome { type ?0 <: org.apache.hadoop.io.compress.CompressionCodec })
--- because ---
argument expression's type is not compatible with formal parameter type;
found : String => Some[Class[?0]] forSome { type ?0 <: org.apache.hadoop.io.compress.CompressionCodec }
required: String => Option[?B]
a.flatMap(codecClassName => {
^
and code
def f(a: Option[String]): Unit = {
a.flatMap(codecClassName => {
val codecFactory = new CompressionCodecFactory(new Configuration())
val codecClass = codecFactory.getCodecClassByName(codecClassName)
if (codecClass == null) {
throw new RuntimeException("Unknown or not supported codec:" + codecClassName)
}
Some(codecClass)
})
}
This seems to be related to the fact that getClass and classOf are not returning the exact same thing. See Scala equivalent of Java java.lang.Class<T> Object for more details.
Looking around for a workaround I came across Scala Getting class type from string representation.
So how about:
val codecClass = Manifest.classType(codecFactory.getCodecClassByName(codecClassName))
This should work. flatMap involves both map and flatten, so it may need more type annotations in some cases. The overall code works after annotation of the function parameter, i.e. (codecClassName: String).
Note the other change -- that flatMap with an inner function returning an Option type is the same as a map if that function returns what's inside the Option (i.e. flattens the option) (see below).
import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.io.compress.{CompressionCodec, CompressionCodecFactory}
...
def f(a: Option[String]): Option[Class[_ <: CompressionCodec]] = {
a.map((codecClassName: String) => {
val codecFactory = new CompressionCodecFactory(new Configuration())
val codecClass = codecFactory.getCodecClassByName(codecClassName)
if (codecClass == null) {
throw new RuntimeException("Unknown or not supported codec:" + codecClassName)
}
codecClass
})
}
To show the relationship between flatMap and map as described above:
scala> val opt: Option[Int] = Some(1)
opt: Option[Int] = Some(1)
scala> opt.map((i: Int) => i + 1)
res0: Option[Int] = Some(2)
scala> val opt2: Option[Int] = None
opt2: Option[Int] = None
scala> opt.flatMap((i: Int) => Some(i + 1))
res1: Option[Int] = Some(2)
scala> opt2.map((i: Int) => i + 1)
res3: Option[Int] = None
scala> opt2.flatMap((i: Int) => Some(i + 1))
res2: Option[Int] = None

Implicit conversion using an intermediary val and map/flatMap

I'm having this implicit def to convert an Option[Int] to an Option[String]
implicit def optIntOptString(n: Option[Int]): Option[String] = Some(n.get.toString)
while this one works:
val optIntVal: Option[Int] = Some(3)
val converted: Option[String] = optIntVal // the 'optIntVal' which is of type Option[Int] gets converted implicitly to Option[String] due to the implicit def 'optIntOptString'
this doesn't:
val failConv: Option[String] = Some(3)
found : Int(3)
required: String
val failConv: Option[String] = Some(3)
I'm trying to do a conversion without using an intermediary val
My intention is to use the implicit conversion within a map/flatmap function, something like:
val someList: List[Int] = List(1, 2, 3)
someList.map((num:Int) => {
val z:Option[String] = Some(num)
z
})
But even with an intermediary val that holds the source type i get an error, seems like the implicit conversion isn't working within the map method:
found : Int
required: String
someList.map((num:Int) => { val z:Option[String] = Some(num); z })

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.

Scala match function against variable

When I'm matching value of case classes, such as:
sealed abstract class Op
case class UOp[T, K](f: T => K) extends Op
case class BOp[T, Z, K](f: (T, Z) => K) extends Op
like this:
def f(op: Op): Int =
op match
{
case BOp(g) => g(1,2)
case UOp(g) => g(0)
}
the compiler infers it as
val g: (Nothing, Nothing) => Any
val g: Nothing => Any
Why am I getting Nothing as the type? Is it because of JVM type erasure? Are there elegant ways to match functions against variables?
I came up with this "hackish" solution, maybe there are other ways or cleaner ways to do this still without relying on reflection.
Define a few partial functions which will handle various args:
scala> val f: PartialFunction[Any, String] = { case (x: Int, y: String) => y * x }
f: PartialFunction[Any,String] = <function1>
scala> val g: PartialFunction[Any, String] = { case x: Int => x.toString }
g: PartialFunction[Any,String] = <function1>
scala> def h: PartialFunction[Any, BigDecimal] = { case (a: Int, b: Double, c: Long) => BigDecimal(a) + b + c }
h: PartialFunction[Any,BigDecimal]
scala> val l: List[PartialFunction[Any, Any]] = f :: g :: h :: Nil
l: List[PartialFunction[Any,Any]] = List(<function1>, <function1>, <function1>)
Check which functions can handle different inputs:
scala> l.map(_.isDefinedAt(1))
res0: List[Boolean] = List(false, true, false)
scala> l.map(_.isDefinedAt((1, "one")))
res1: List[Boolean] = List(true, false, false)
Given input find and apply a function:
scala> def applyFunction(input: Any): Option[Any] = {
| l find (_.isDefinedAt(input)) map (_ (input))
| }
applyFunction: (input: Any)Option[Any]
scala> applyFunction(1)
res1: Option[Any] = Some(1)
scala> applyFunction((2, "one"))
res2: Option[Any] = Some(oneone)
scala> applyFunction("one")
res3: Option[Any] = None
scala> applyFunction(1, 1.1, 9L)
res10: Option[Any] = Some(11.1)
This looks quite type unsafe and there must be better ways to do this.
I think magnet pattern should handle this well in more typesafe manner.

String to Int in Scala

Suppose I need to convert a String to Int in Scala. If the string is not a number I would like to return None rather than throw an exception.
I found the following solution
def toMaybeInt(s:String) = {
import scala.util.control.Exception._
catching(classOf[NumberFormatException]) opt s.toInt
}
Does it make sense ? Would you change/improve it ?
I'd use scala.util.Try which returns Success or Failure for a computation that may throw an exception.
scala> val zero = "0"
zero: String = 0
scala> val foo = "foo"
foo: String = foo
scala> scala.util.Try(zero.toInt)
res5: scala.util.Try[Int] = Success(0)
scala> scala.util.Try(foo.toInt)
res6: scala.util.Try[Int] = Failure(java.lang.NumberFormatException: For input string: "foo")
So, toMaybeInt(s: String) becomes:
def toMaybeInt(s:String) = {
scala.util.Try(s.toInt)
}
For getting an option in any case, regardless of possible exceptions due to number malformation,
import scala.util.Try
def toOptInt(s:String) = Try(s.toInt) toOption
Then
scala> toOptInt("123")
res2: Option[Int] = Some(123)
scala> toOptInt("1a23")
res3: Option[Int] = None
Further, consider
implicit class convertToOptInt(val s: String) extends AnyVal {
def toOptInt() = Try(s.toInt) toOption
}
Hence
scala> "123".toOptInt
res5: Option[Int] = Some(123)
scala> "1a23".toOptInt
res6: Option[Int] = None