More concise Scala extractor definition syntax - scala

Extractors can be an incredibly useful way to reduce duplication in pattern matching code, however, often the logic contained in them is just a simple one-line pattern that needed to be DRYed out from the code, for example, I had a recurring pattern of Person(_, _, Some(Position(_, Some(company)))), so I came up with this extractor:
object EmployedAt {
def unapply(x: Person): Option[Company] = x match {
case Person(_, _, Some(Position(_, company))) => company
case _ => None
}
}
which I could then use like this:
val companies = people.collect { case EmployedAt(c) => c }.distinct
def numEmployees(company: Company) =
people.collect { case EmployedAt(`company`) => }.size
people.collect { case p # EmployedAt(c) if numEmployees(c) >= 2 => (p, c) }
etc — all very nice, concise and readable... except for the extractor implementation itself. The problem I'm seeing is that, ultimately, the extractor just boils down to the 1st case statement, and the rest is just boilerplate. Instead, I think the following would be much more desirable for defining simple (possibly one-off or twice-off) extractors:
def EmployedAt(x: Person): Company = {
case Person(_, _, Some(Position(_, Some(company)))) => company
}
...which is 2 full lines instead of 4.
— how would I go about DRYing up the boilerplate to come to something as concise as the above?

I immediately started playing around with potential solutions and I think I've come to quite a nice one, which, in addition to allowing the definition of extractors without the object+unapply+Option[T]+case _ => None boilerplate, also makes it immediately obvious to the reader that a given function is an extractor, as well as statically marking it as an Extractor:
trait Extractor[T, U] { def unapply(x: T): Option[U] }
object Extractor {
def apply[T, U](f: PartialFunction[T, U]) = new Extractor[T, U] {
def unapply(x: T) = f.lift(x)
}
}
val EmployedAt = Extractor[Person, Company] {
case Person(_, _, Some(Position(_, Some(company)))) => company
}
I did not have the intention to immediately answer my own question but this is how it turned out. I'm still open to criticism and other suggestions from potentially more competent Scala community members! :)

Related

How to negate types in pattern match in Scala?

With this code println will be executed only for specified exception. I'm wondering if it's possible to negate that line to make it executed for all other exceptions that are not specified. I know it's possible using 2 cases, but I want to know if it can be done with one case.
val myHandler: PartialFunction[Throwable, Unit] = {
case e # (_: MappingException | _: ParseException | _: SomeOtherException) =>
println("Got it")
}
AFAIk you can not do this with a single match, but you can create your own custom Extractor in case you need to replicate this behaviour in multiple places.
import scala.reflect.ClassTag
final class Not[A : ClassTag] {
def unapply(any: Any): Boolean = any match {
case _: A => false
case _ => true
}
}
object Not {
def apply[A : ClassTag]: Not[A] = new Not
}
which you can use like this:
final val NotAnInt = Not[Int]
10 match {
case NotAnInt() => false
case _ => true
}
// res: Boolean = true
"10" match {
case NotAnInt() => true
case _ => false
}
// res: Boolean = true
However, keep in mind this will have all the limitation of any type check, like not being able to differentiate between a List[Int] from a List[String] due erasure; and being considered a bad practice.
I would suggest looking into a typeclass approach, for example, I believe Shapeless provides a negation one.
You can see the code running here.
Well you've already identified what is probably the more readable way to do it.
val myHandler: PartialFunction[Throwable, Unit] = {
case e # (_: MappingException | _: ParseException | _: SomeOtherException) =>
throw e
case _ =>
println("Got it")
}
This is probably how I'd write this in actual production code. It's sensible and it's clear at a glance.
But you asked for one case, so let's give that a go. Since we want to check against several types, we'll need to be able to represent them as a list. There are countless Scala libraries that make this prettier, but for our purposes we'll just roll our own.
trait TList {
def isMember(x: Any): Boolean
}
object Nil extends TList {
def isMember(x: Any) = false
}
case class Cons[H : ClassTag](val tail: TList) extends TList {
def isMember(x: Any) = {
x match {
case _: H => true
case _ => tail.isMember(x)
}
}
}
So we can represent classical Lisp-style singly-linked lists and check whether an arbitrary Any value has a type anywhere in the list. Now let's negate it and write an unapply method.
case class NotMember(val types: TList) {
def unapply(elem: Any): Boolean =
!types.isMember(elem)
}
Then our handler looks like
val test = NotMember(
Cons[MappingException](Cons[ParseException](Cons[SomeOtherException](Nil)))
)
val myHandler: PartialFunction[Throwable, Unit] = {
case test() =>
println("Got it")
}
Again, if you really want to go down this road, you'll want to grab a library to make the type-level stuff manageable. But it's definitely possible. The only question is whether it's worth it for your use case.

Functional composition of different types of Tasks - Scala

Currently, I am working on a design to build a generic pipeline in Scala (purely for learning purposes). For this, I started with a basic construct, Task which takes some TaskConfiguration (for now, we can assume that this TaskConfiguration is a case class which is specific to the Task functionality). Trait structure is as follows:
trait Task[T <: TaskConfiguration] {
type Out
def taskConfiguration: T
def execute(previousOutput: Option[Out]): Option[Out]
}
Requirements:
1. I could have multiple Tasks which are extending Task trait. Like, ReadTask, WriteTask, etc.,
2. Every task will have it's own type for "out"
My question is: Given a List[Task], how could I compose the method calls to execute. Tried multiple ways to compose them but I keep getting issue where I could not distinguish between previous task's out with the current task's out, given I have only one type member to specify what this task could handle.
I hope we could solve this with Scala. But given the fact that, I am pretty new to Functional Programming with Scala, I couldn't figure it out. Thank you very much in advance.
Note: Description to this question might seem a bit out of context. But this is the best I could come up with, at this point of time. Feel free to edit this, if you think we could make it better. If you think this question doesn't make any sense, please mention it in the comments with your thoughts, so that I could take care of it.
You could use a pattern similarly to andThen from Scala's functions.
I compiled a little example:
import scala.util.{Try, Success, Failure}
type TaskConfiguration = Any
trait Task[-C <: TaskConfiguration, +O <: TaskConfiguration] {
def execute(configuration: C): Option[O]
def andThen[O2 <: TaskConfiguration](secondTask: Task[O, O2]): Task[C, O2] = {
val firstTask = this
new Task[C, O2] {
def execute(configuration: C): Option[O2] =
firstTask.execute(configuration).flatMap(secondTask.execute(_))
}
}
}
// From here on it's the example!
case class UnparsedNumber(value: String)
trait ParsedNumber {
val value: Int
}
case class ParsedPositiveNumber(int: Int) extends ParsedNumber {
val value: Int = int
}
case class HumanReadableNumber(value: String)
val task1 = new Task[UnparsedNumber, ParsedPositiveNumber] {
def execute(configuration: UnparsedNumber): Option[ParsedPositiveNumber] = {
Try(configuration.value.toInt) match {
case Success(i) if i >= 0 => Some(ParsedPositiveNumber(i))
case Success(_) => None
case Failure(_) => None
}
}
}
val task2 = new Task[ParsedNumber, HumanReadableNumber] {
def execute(configuration: ParsedNumber): Option[HumanReadableNumber] = {
if(configuration.value < 1000 && configuration.value > -1000)
Some(HumanReadableNumber(s"The number is $configuration"))
else
None
}
}
val combined = task1.andThen(task2)
println(combined.execute(UnparsedNumber("12")))
println(combined.execute(UnparsedNumber("12x")))
println(combined.execute(UnparsedNumber("-12")))
println(combined.execute(UnparsedNumber("10000")))
println(combined.execute(UnparsedNumber("-10000")))
Try it out!
Edit:
Regarding your comments, this approach might be more what you're looking for:
case class Task[-C, +O](f: C => Option[O]) {
def execute(c: C): Option[O] = f.apply(c)
}
case class TaskChain[C, O <: C](tasks: List[Task[C, O]]) {
def run(initial: C): Option[O] = {
def runTasks(output: Option[C], tail: List[Task[C, O]]): Option[O] = {
output match {
case Some(o) => tail match {
case head :: Nil => head.execute(o)
case head :: tail => runTasks(head.execute(o), tail)
case Nil => ??? // This should never happen!
}
case None => None
}
}
runTasks(Some(initial), tasks)
}
}
// Example below:
val t1: Task[Int, Int] = Task(i => Some(i * 2))
val t2: Task[Int, Int] = Task(i => Some(i - 100))
val t3: Task[Int, Int] = Task(i => if(i > 0) Some(i) else None)
val chain: TaskChain[Int, Int] = TaskChain(List(t1, t2, t3))
println(chain.run(100))
println(chain.run(10))
Try it out!
Quote:
What you need to understand is that if you pack your Tasks in a List[Task] and use it as a chain of Tasks, the output has to be at least a subtype of the input. C <: TaskConfiguration and O <: C leads to: O <: C <: TaskConfiguration which also means O <: TaskConfiguration.
If you don't understand any part of this I will be happy to further explain.
I hope this helps.
I would suggest taking a look about what cats and free monads can offer to you. Following that approach, I would start defining an ADT for defining pipeline programs. Something like :
trait TaskE[Effect]
case class ReadTask[Input, SourceConfig](source: SourceConfig) extends TaskE[Input]
case class WriteTask[Output, SinkConfig](out: Output, sink: SinkConfig) extends TaskE[Unit]
And then apply Free monads (as mentioned in above link) for defining your pipeline flow. Something like:
val pipeline: Task[Unit] =
for {
input1 <- read(source1)
input2 <- read(source2)
_ <- write(input1 + input2, sink1)
} yield ()
Now it will depend on the compiler (it's a natural transformation that describes how to convert from Task[A] to F[A], and F may be Id,Try, Future, ...) you define how this program will run:
val myCompiler: Task ~> Id = ???
val tryCompiler: Task ~> Try = ???
pipeline.foldMap(myCompiler) // Id[Unit]
pipeline.foldMap(tryCompiler) // Try[Unit]
You could have as many 'compilers' as you want and that doesn't imply changing your pipeline ('program') definition.

Is there a concise way to "invert" an Option?

Say I have a function that can take an optional parameter, and I want to return a Some if the argument is None and a None if the argument is Some:
def foo(a: Option[A]): Option[B] = a match {
case Some(_) => None
case None => Some(makeB())
}
So what I want to do is kind of the inverse of map. The variants of orElse are not applicable, because they retain the value of a if it's present.
Is there a more concise way to do this than if (a.isDefined) None else Some(makeB())?
fold is more concise than pattern matching
val op:Option[B] = ...
val inv = op.fold(Option(makeB()))(_ => None)
Overview of this answer:
One-liner solution using fold
Little demo with the fold
Discussion of why the fold-solution could be just as "obvious" as the if-else-solution.
Solution
You can always use fold to transform Option[A] into whatever you want:
a.fold(Option(makeB())){_ => Option.empty[B]}
Demo
Here is a complete runnable example with all the necessary type definitions:
class A
class B
def makeB(): B = new B
def foo(a: Option[A]): Option[B] = a match {
case Some(_) => None
case None => Some(makeB())
}
def foo2(a: Option[A]): Option[B] =
a.fold(Option(makeB())){_ => Option.empty[B]}
println(foo(Some(new A)))
println(foo(None))
println(foo2(Some(new A)))
println(foo2(None))
This outputs:
None
Some(Main$$anon$1$B#5fdef03a)
None
Some(Main$$anon$1$B#48cf768c)
Why fold only seems less intuitive
In the comments, #TheArchetypalPaul has commented that fold seems "lot less obvious" than the if-else solution. I agree, but I still think that it might be interesting to reflect on the reasons why that is.
I think that this is mostly an artifact resulting from the presence of special if-else syntax for booleans.
If there were something like a standard
def ifNone[A, B](opt: Option[A])(e: => B) = new {
def otherwise[C >: B](f: A => C): C = opt.fold((e: C))(f)
}
syntax that can be used like this:
val optStr: Option[String] = Some("hello")
val reversed = ifNone(optStr) {
Some("makeB")
} otherwise {
str => None
}
and, more importantly, if this syntax was mentioned on the first page of every introduction to every programming language invented in the past half-century, then the ifNone-otherwise solution (that is, fold), would look much more natural to most people.
Indeed, the Option.fold method is the eliminator of the Option[T] type: whenever we have an Option[T] and want to get an A out of it, the most obvious thing to expect should be a fold(a)(b) with a: A and b: T => A. In contrast to the special treatment of booleans with the if-else-syntax (which is a mere convention), the fold method is very fundamental, the fact that it must be there can be derived from the first principles.
I've come up with this definition a.map(_ => None).getOrElse(Some(makeB())):
scala> def f[A](a: Option[A]) = a.map(_ => None).getOrElse(Some(makeB()))
f: [A](a: Option[A])Option[makeB]
scala> f(Some(44))
res104: Option[makeB] = None
scala> f(None)
res105: Option[makeB] = Some(makeB())
I think the most concise and clearest might be Option.when(a.isEmpty)(makeB)

How to use for instead of flatMap/map in Scala?

I'm in stack to understand how Scala for works.
I think codes below could be written with for though I don't have any idea how.
Could someone explain me how I can do that?
def foo: Future[Option[Int]] = ???
def bar: Future[Throwable Xor Option[Int]] = ???
def baz: Future[Option[Boolean]] = ???
foo.flatMap {
case Some(x) =>
Future.successful(x)
case None =>
bar.flatMap {
case Xor.Right(Some(x)) =>
baz.map {
case true => 1
case false => 0
}
case Xor.Right(None) =>
Future.successful(0)
case Xor.Left(_) =>
Future.successful(-1)
}
}
With all the branching inside the flatMap functions, it won't be possible to write this as a for comprehension.
It is possible to replace pattern matching with a fold method, but this may be a matter of personal preference.
Option("suish") match {
case Some(name) => s"hello $name"
case None => "hello world"
}
// is analogous to
Option("suish").fold("hello world")(name => s"hello $name")
I rewrote your pattern matching using the fold methods of OptionT (tutorial), XorT and Option, but I'm not sure if this is more readable than your nested pattern matches.
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import cats.implicits._
import cats.data.{Xor, XorT, OptionT}
def foo: Future[Option[Int]] = none[Int].pure[Future]
def bar: Future[Throwable Xor Option[Int]] = 2.some.right.pure[Future]
def baz: Future[Option[Boolean]] = true.some.pure[Future]
OptionT(foo).getOrElseF {
// foo : case None
XorT(bar).fold(
// bar : case Xor.Left
_ => -1.pure[Future],
barO => barO.fold(
// bar : case Xor.Right(None)
0.pure[Future])(
// bar : case Xor.Right(Some(x))
_ => baz.map(_.fold(0 /* ? */)(b => if (b) 1 else 0)))
).flatten
}
// Future[Int]
It is not possible to pattern match in for-comprehensions. See Allow pattern matching on type in for comprehensions.
Perhaps you can use Monad Transformers. I do want to implement your code in that manner, but I don't have time for that now. Maybe the hint can help you.
/Edit This is not completely correct as pointed out by the comment of Sergey. You can pattern match in for-comprehensions as long as all matches are of the same type. See this image taken from the second lesson of the first week of Functional Program Design in Scala Coursera Course where all patterns inherit from JSON:

Scala type mismatch while trying to pass a function

I need some help trying to figure out how to reuse a pattern match that I would rather not repeat (if possible). I have searched here and google, experimented with implicits and variance but to no result so far.
In the below are 2 methods, doSomething and doSomethingElse that contain the same pattern match on Ids. I would like to reuse the pattern by passing in a function.
This the initial setup. (The actual implementations of toPath and take2 are not really relevant.)
import java.nio.file.{Paths, Path}
import java.util.UUID
def take2(x: Long): String = {
(x % 100).toString.padTo(2, '0')
}
def take2(u: UUID): String = {
u.toString.take(2)
}
def toPath(x: Long): Path = {
Paths.get(s"$x")
}
def toPath(u: UUID): Path = {
Paths.get(u.toString)
}
case class Ids(id1: Option[Long], id2: Option[UUID])
def doSomething(ids: Ids): String = ids match {
case Ids(_, Some(uuid)) => take2(uuid)
case Ids(Some(long), _) => take2(long)
}
def doSomethingElse(ids: Ids) = ids match {
case Ids(_, Some(uuid)) => toPath(uuid)
case Ids(Some(long), _) => toPath(long)
}
doSomething(Ids(Some(12345L), None))
doSomethingElse(Ids(Some(12345L), None))
What I would like is for something like this to work:
def execute[A](ids: Ids)(f: Any => A): A = ids match {
case Ids(_, Some(uuid)) => f(uuid)
case Ids(Some(long), _) => f(long)
}
def _doSomething(ids: Ids) = execute[String](ids)(take2)
//def _doSomething2(ids: Ids) = execute[Path](ids)(toPath)
The error I get is:
Error: ... type mismatch;
found : (u: java.util.UUID)String <and> (x: Long)String
required: Any => String
def _doSomething(ids: Ids) = execute[String](ids)(take2)
^ ^
How can I make these function types work please?
My Scala version 2.11.2.
Worksheet I have been using:
https://github.com/lhohan/scala-pg/blob/0f1416a6c1d3e26d248c0ef2de404bab76ac4e57/src/main/scala/misc/MethodPassing.sc
Any help or pointers are kindly appreciated.
The problem is that you have two different methods that just happen to share the same name, e.g. "take2". When you try to use take2 you certainly aren't providing a function that can handle any argument type (as Any => A demands); you can't even handle the two types you want since they are two different methods!
In your original match statement you don't notice that the two methods are two methods that share the same name because the compiler fills in the correct method based on the argument type. There isn't a feature that says, "plug in the name I supply and then stick in different methods". (Well, you could do it with macros, but that's awfully complicated to avoid a little bit of repetition.)
Now the compiler is smart enough to make a function out of the method you want. So if you wrote
def execute[A](ids: Ids)(f1: UUID => A, f2: Long => A): A = ids match {
case Ids(_, Some(uuid)) => f1(uuid)
case Ids(Some(long), _) => f2(long)
}
you could then
def doSomething(ids: Ids) = execute[String](ids)(take2, take2)
which would reduce the repetition a bit.
Alternatively, you could write
import scala.util._
def take2(x: Long): String = (x % 100).toString.padTo(2, '0')
def take2(u: UUID): String = u.toString.take(2)
def take2(ul: Either[UUID, Long]): String = ul match {
case Left(u) => take2(u)
case Right(l) => take2(l)
}
(be sure to use :paste if you try this out in the REPL so all three get defined together).
Then you write
def execute[A](ids: Ids)(f: Either[UUID, Long] => A): A = ids match {
case Ids(_, Some(uuid)) => f(Left(uuid))
case Ids(Some(long), _) => f(Right(long))
}
and the correct one of the three take2s will be used. (There is a runtime penalty associated with the extra boxing of the arguments, but I doubt that this is a performance-critical code path.)
There are other options as well--Shapeless, for instance, provides union types. Or you can do runtime pattern matching and throw an exception if you pass something that is neither UUID nor Long...but that is liable to be a recipe for trouble later.