Combine 2 partial functions - scala

I have two partial functions returning unit (f1, f2). For instance, something like that:
val f1 = {
case s: arg => //do some
//etc... lots of cases
}
val f2 = {
case s: anotherArg => //do some
//lots of cases
}
Is there a concise way to compose this to partial functions the way as that if
f(x) = {f1(x); f2(x)} iff f1.isDefinedAt(x) && f2.isDefinedAt(x)
f(x) = f1(x); iff f1.isDefinedAt(x) && !f2.isDefinedAt(x)
f(x) = f2(x); iff !f1.isDefinedAt(x) && f2.isDefinedAt(x)

orElse
f1 orElse f2
Scala REPL
scala> val f: PartialFunction[Int, Int] = { case 1 => 1 }
f: PartialFunction[Int,Int] = <function1>
scala> val g: PartialFunction[Int, Int] = { case 2 => 2 }
g: PartialFunction[Int,Int] = <function1>
scala> val h = f orElse g
h: PartialFunction[Int,Int] = <function1>
scala> h(1)
res3: Int = 1
scala> h(2)
res4: Int = 2
scala> h.isDefinedAt(1)
res6: Boolean = true
scala> h.isDefinedAt(2)
res7: Boolean = true
Both both functions to execute on common cases
Using List of partial functions and foldLeft
Scala REPL
scala> val f: PartialFunction[Int, Int] = { case 1 => 1 case 3 => 3}
f: PartialFunction[Int,Int] = <function1>
scala> val g: PartialFunction[Int, Int] = { case 2 => 2 case 3 => 3}
g: PartialFunction[Int,Int] = <function1>
scala> val h = f orElse g
h: PartialFunction[Int,Int] = <function1>
scala> h(3)
res10: Int = 3
scala> h(3)
res11: Int = 3
scala> val h = List(f, g)
h: List[PartialFunction[Int,Int]] = List(<function1>, <function1>)
scala> def i(arg: Int) = h.foldLeft(0){(result, f) => if (f.isDefinedAt(arg)) result + f(arg) else result }
i: (arg: Int)Int
scala> i(3)
res12: Int = 6

Although pamu's answer is good, I don't like the fact that it is bound to specific Int type. Unfortunately you didn't specify result type well enough, so I see 3 alternatives:
You want to get list of all results of all defined functions and you don't care about which function produced which result. In this case something like this would work:
def callAll[A, B](funcs: List[PartialFunction[A, B]], a: A): List[B] = funcs.foldRight(List.empty[B])((f, acc) => if (f.isDefinedAt(a)) f.apply(a) :: acc else acc)
if order of elements is not important you may use
def callAll[A, B](funcs: List[PartialFunction[A, B]], a: A): List[B] = funcs.foldLeft(List.empty[B])((f, acc) => if (f.isDefinedAt(a)) f.apply(a) :: acc else acc)
which probably will be a bit faster
You want to get Option with Some in case corresponding function is defined at the point or None otherwise. In such case something like this would work:
def callAllOption[A, B](funcs: List[PartialFunction[A, B]], a: A): List[Option[B]] = funcs.map(f => f.lift.apply(a))
If you don't want to create List explicitly, you can use varargs such as:
def callAllOptionVarArg[A, B](a: A, funcs: PartialFunction[A, B]*): List[Option[B]] = funcs.map(f => f.lift.apply(a)).toList
or such curried version to specify value after functions:
def callAllOptionVarArg2[A, B](funcs: PartialFunction[A, B]*)(a: A): List[Option[B]] = funcs.map(f => f.lift.apply(a)).toList
You call functions purely for side effects and return value is not important, in which case you can safely use second (a bit faster) callAll definition
Examples:
val f: PartialFunction[Int, Int] = {
case 1 => 1
case 3 => 3
}
val g: PartialFunction[Int, Int] = {
case 2 => 2
case 3 => 4
}
val fl = List(f, g)
println(callAll(fl, 1))
println(callAll(fl, 3))
println(callAllOption(fl, 2))
println(callAllOptionVarArg(1, f, g))
println(callAllOptionVarArg2(f, g)(3))
List(1)
List(3, 4)
List(None, Some(2))
List(Some(1), None)
List(Some(3), Some(4))

Related

Scala method that takes a function as a parameter and then executes it

I want to write a simple method that takes a function as a parameter and then executes it.
def exec(f: (a:Int, b:Int) => Boolean): Boolean = f(a,b)
I'm not sure what is wrong with the above, but I get the error:
<console>:1: error: ')' expected but ':' found.
def exec(f: (a:Int, b:Int) => Boolean): Boolean = f(a,b)
^ ^
| |
// These are supposed to be types, but a: Int and b: Int aren't types,
// they are identifiers with type ascriptions.
It should look a little more like:
def exec(f: (Int, Int) => Boolean): Boolean = f(a, b)
Now f is a function (Int, Int) => Boolean. But this doesn't compile, because a and b are not defined.
You either need to pass them in, or fix them to a value.
def exec(a: Int, b: Int)(f: (Int, Int) => Boolean): Boolean = f(a, b)
scala> exec(2, 3)(_ > _)
res1: Boolean = false
If you want to execute a function with parameters in your exec method you need to:
scala> def exec(f: => Unit) = {
| println("Exec:")
| f
| }
scala> def foo(f : (Int, Int)): Unit = println(f._1 + f._2)
scala> exec(foo((3, 4)))
Exec:
7
because foo((3, 4)) type is => Unit
Not quite an answer to your original question (and too big to be a comment), but if you're looking to write a tasteful, nice-looking execution operator and don't particularly like the syntax of the provided answers, perhaps something similar to scalaz's pipe operator (|>) might be what you're thinking of?
scala> // You could just get this from scalaz with import scalaz._ and import Scalaz._
scala> implicit class FancyExec[A](x: A){def |>[B](f: A => B) = f(x)}
scala> 5 |> (_ + 6)
res1: Int = 11
scala> (5, 4) |> ((_: Int) < (_: Int)).tupled
res2: Boolean = false
scala> val f = ((_: Int) < (_: Int)).tupled
f: ((Int, Int)) => Boolean = <function1>
scala> val g = ((_: Int) > (_: Int)).tupled
g: ((Int, Int)) => Boolean = <function1>
scala> List(f, g) map ((5, 4) |> _)
res3: List[Boolean] = List(false, true)

Keeping intermediate results of function composition

Suppose I've got the following three functions:
val f1: Int => Option[String] = ???
val f2: String => Option[Int] = ???
val f3: Int => Option[Int] = ???
I can compose them as follows:
val f: Int => Option[Int] = x =>
for {
x1 <- f1(x)
x2 <- f2(x1)
x3 <- f3(x2)
} yield x3
Suppose now that I need to keep the intermediate results of execution f1, f2, f3 and pass them to the caller:
class Result(x: Int) {
val r1 = f1(x)
val r2 = r1 flatMap f2
val r3 = r2 flatMap f3
def apply = r3
}
val f: Int => Result = x => new Result(x)
Does it make sense ? How would you improve/simplify this solution ?
Homogenous List
It's pretty simple for single type, suppose
val g1: Int => Option[Int] = x => if (x % 2 == 1) None else Some(x / 2)
val g2: Int => Option[Int] = x => Some(x * 3 + 1)
val g3: Int => Option[Int] = x => if (x >= 4) Some(x - 4) else None
You can define
def bind[T]: (Option[T], T => Option[T]) => Option[T] = _ flatMap _
def chain[T](x: T, fs: List[T => Option[T]]) = fs.scanLeft(Some(x): Option[T])(bind)
And now
chain(4, g1 :: g2 :: g3 :: Nil)
will be
List(Some(4), Some(2), Some(7), Some(3))
preserving all intermediate values.
Heterogenous List
But we can do if there are multiple types involved?
Fortunately there is shapeless library for special structures named Heterogenous List which could handle list-like multi-typed sequences of values.
So suppose we have
import scala.util.Try
val f1: Int => Option[String] = x => Some(x.toString)
val f2: String => Option[Int] = x => Try(x.toInt).toOption
val f3: Int => Option[Int] = x => if (x % 2 == 1) None else Some(x / 2)
Lets define heterogenous analogues to previous functions:
import shapeless._
import ops.hlist.LeftScanner._
import shapeless.ops.hlist._
object hBind extends Poly2 {
implicit def bind[T, G] = at[T => Option[G], Option[T]]((f, o) => o flatMap f)
}
def hChain[Z, L <: HList](z: Z, fs: L)
(implicit lScan: LeftScanner[L, Option[Z], hBind.type]) =
lScan(fs, Some(z))
And now
hChain(4, f1 :: f2 :: f3 :: HNil)
Evaluates to
Some(4) :: Some("4") :: Some(4) :: Some(2) :: HNil
Class converter
Now if you urged to save your result in some class like
case class Result(init: Option[Int],
x1: Option[String],
x2: Option[Int],
x3: Option[Int])
You could easily use it's Generic representation
just ensure yourself that
Generic[Result].from(hChain(4, f1 :: f2 :: f3 :: HNil)) ==
Result(Some(4),Some("4"),Some(4),Some(2))

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.

Match Error on List.collect

What's wrong with the second implementation?
Works:
scala> List(1,2,3).collect{ case i: Int if i % 2 == 0 => i }
res1: List[Int] = List(2)
Doesn't:
scala> val evens = PartialFunction[Any, Int]{
| case i: Int if i % 2 == 0 => i
| }
evens: PartialFunction[Any,Int] = <function1>
scala> List(1,2,3).collect{evens}
scala.MatchError: 1 (of class java.lang.Integer)
at $anonfun$1.apply(<console>:7)
at $anonfun$1.apply(<console>:7)
at scala.PartialFunction$$anonfun$apply$1.applyOrElse(PartialFunction.scala:242)
at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:33)
at scala.collection.TraversableLike$$anonfun$collect$1.apply(TraversableLike.scala:278)
at scala.collection.immutable.List.foreach(List.scala:318)
...
You should create evens PartialFunction like this:
val evens: PartialFunction[Any, Int] = {
case i: Int if i % 2 == 0 => i
}
With PartialFunction[Any, Int]{ ... } you are calling an apply method of object PartialFunction. It defined like this:
def apply[A, B](f: (A) ⇒ B): PartialFunction[A, B]
So { case i: Int if i % 2 == 0 => i } is used as a function, not a PartialFunction and evens is defined at any argument:
scala> val evens = PartialFunction[Any, Int]{
| case i: Int if i % 2 == 0 => i
| }
scala> evens.isDefinedAt(1)
res1: Boolean = true
scala> val evens: PartialFunction[Any, Int] = {
| case i: Int if i % 2 == 0 => i
| }
scala> evens.isDefinedAt(1)
res5: Boolean = false
Your code actually does work on Scala 2.9.2 (modulo incorrect partial function declaration). However, in any case the reason is probably the type signature:
PartialFunction[Any, Int]
Since the first type parameter is Any, the collection elements get autoboxed to java.lang.Integer instances - it even says so in the stack trace (by necessity, since Any corresponds to Object). However, you're matching for Int, and this causes the error.
Using PartialFunction[Int, Int] should solve the problem, i.e.:
val evens:PartialFunction[Int, Int] = {case i: Int if i % 2 == 0 => i}

Canonical way to work on Option elements in Scala

As an example, I want to apply a function f: (Int,Int) => Int to two elements of type Option[Int]. My thoughts were something like (a,b).zipped.map(f), but this yields a List, and I want to get a new Option[Int] as result.
scala> def f(a:Int,b:Int) = a*b
f: (a: Int, b: Int)Int
scala> val x = Some(42)
x: Some[Int] = Some(42)
scala> val y:Option[Int] = None
y: Option[Int] = None
scala> (x,y).zipped.map(f)//I want None as a result here
res7: Iterable[Int] = List()
How can this be done without explicitly branching?
Just like many other operations in scala this can be done via for comprehension:
def f(a:Int,b:Int) = a*b
for (x <- maybeX; y <- maybeY) yield f(x, y)
As often is the case with this type of question, scalaz has some help:
scala> import scalaz._
import scalaz._
scala> import Scalaz._
import Scalaz._
scala> def f(a:Int,b:Int) = a*b
f: (a: Int, b: Int)Int
scala> val x = Some(42)
x: Some[Int] = Some(42)
scala> val y:Option[Int] = None
y: Option[Int] = None
scala> ^(x,y)(f)
res0: Option[Int] = None
scala> val x = 42.some
x: Option[Int] = Some(42)
scala> (x |#| y)(f)
res3: Option[Int] = None
Using om-nom-nom's idea, I can do something like this:
scala> def f(a:Int,b:Int) = a*b
f: (a: Int, b: Int)Int
scala> def lifted(f: (Int,Int) => Int) = (a:Option[Int],b:Option[Int]) => for(x<-a;y<-b) yield f(x,y)
lifted: (f: (Int, Int) => Int)(Option[Int], Option[Int]) => Option[Int]
scala> def liftedF = lifted(f)
liftedF: (Option[Int], Option[Int]) => Option[Int]
scala> val x = Some(42)
x: Some[Int] = Some(42)
scala> val y:Option[Int] = None
y: Option[Int] = None
scala> liftedF(x,x)
res0: Option[Int] = Some(1764)
scala> liftedF(x,y)
res2: Option[Int] = None
We can even generalize this...please cover your eyes:
def lift2[A, B, C](f: (A, B) => C): (Option[A], Option[B]) => Option[C] = (a: Option[A], b: Option[B]) =>
for (x <- a; y <- b) yield f(x, y)