def macro inside case statement - scala

I'd like to ask where def macros can be called and when they are expanded? I guess we cant just put an appropriate generated AST anywhere it fits?
For example, I want this:
(2,1) match {
case StandaloneMacros.permutations(1,2) => true ;
case (_,_) => false
}
become this after macro expansion
(2,1) match {
case (1,2) | (2,1) => true ;
case (_,_) => false
}
My macro permutations produces an Alternative of tuples. But when I run the first snippet, I get
macro method permutations is not a case class, nor does it have an unapply/unapplySeq member
I also tried defining a Permutations object with unapply macro method but got another error:
scala.reflect.internal.FatalError: unexpected tree: class scala.reflect.internal.Trees$Alternative
So: Is it possible to achieve at all?

I came up with a solution some time ago, and I thought I'd share it with you.
To achieve above task I've used a Transformer and transformCaseDefs
object Matcher {
def apply[A, B](expr: A)(patterns: PartialFunction[A, B]): B = macro apply_impl[A,B]
def apply_impl[A: c.WeakTypeTag, B: c.WeakTypeTag](c: Context)(expr: c.Expr[A])(patterns: c.Expr[PartialFunction[A, B]]): c.Expr[B] = {
import c.universe._
def allElemsAreLiterals(l: List[Tree]) = l forall {
case Literal(_) | Ident(_) => true
case _ => throw new Exception("this type of pattern is not supported")
}
val transformer = new Transformer {
override def transformCaseDefs(trees: List[CaseDef]) = trees.map {
case cas # CaseDef(pat # Apply(typTree, argList), guard, body) if allElemsAreLiterals(argList) =>
val permutations = argList.permutations.toList.map(t => q"(..$t)").map {
case Apply(_, args) => Apply(typTree, args)
}
val newPattern = Alternative(permutations)
CaseDef(newPattern, guard, body)
case x => x
}
}
c.Expr[B](q"${transformer.transform(patterns.tree)}($expr)")
}
}
It would be shorter, but somehow you need to provide the same TypeTree which was used in original (before transformation) case statement.
This way, it can be used like this
val x = (1,2,3)
Matcher(x) {
case (2,3,1) => true
case _ => false
}
which is then translated to something like
val x = (1,2,3)
x match {
case (1,2,3) | (1,3,2) | (2,1,3) | (2,3,1) | (3,1,2) | (3,2,1) => true
case _ => false
}

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.

Surprising PartialFunction literal

I just got puzzled by the fact that this partial function pf doesn't blow up with a MatchError when inner is not InnerA
sealed trait Inner
case class InnerA(name: String) extends Inner
case class InnerB(name: String, value: Int) extends Inner
case class Input(id: String, inner: Inner)
case class Output(id: String, inner: InnerA)
val pf: PartialFunction[Input, Output] = { input =>
input.inner match {
case innerA: InnerA =>
val Input(id, _) = input
Output(id, innerA)
}
}
instead it is simply undefined so this passes
Seq(
Input("1", InnerA("a1")),
Input("2", InnerB("b2", 2)),
Input("3", InnerA("a3"))
).collect(pf) shouldBe Seq(
Output("1", InnerA("a1")),
Output("3", InnerA("a3"))
)
If I add a line I get a compilation warning and trying to pass an InnerB in the collect above throws a MatchError (as I originally expected):
val pf: PartialFunction[Input, Output] = { input =>
println(input)
input.inner match {
case innerA: InnerA =>
val Input(id, _) = input
Output(id, innerA)
}
}
InnerB(b2,2) (of class casa.InnerB)
scala.MatchError: InnerB(b2,2) (of class casa.InnerB)
Why is this? Is this quirk documented somewhere?
(I'm using Scala 2.13.3)
What is happening is that, in the first case, the compiler is "removing" the input match from and using input.inner.
When I run scalac -Xprint:typer Test.scala, the first code turns into:
final override def applyOrElse[A1 <: Input, B1 >: Output](input: A1, default: A1 => B1): B1 = (input.inner: Inner #unchecked) match {
case (innerA # (_: InnerA)) => {
val id: String = (input: A1 #unchecked) match {
case (id: String, inner: Inner): Input((id # _), _) => id
};
Output.apply(id, innerA)
}
case (defaultCase$ # _) => default.apply(input)
};
final def isDefinedAt(input: Input): Boolean = (input.inner: Inner #unchecked) match {
case (innerA # (_: InnerA)) => true
case (defaultCase$ # _) => false
}
Which means that your function will behave like a PartialFunction[Inner, Output], so the compiler knows that it doesn't need to warn you that your match is not exhaustive.
On the other hand, when you see the results for the method with the print instruction, you get:
final override def applyOrElse[A1 <: Input, B1 >: Output](input: A1, default: A1 => B1): B1 = ((input.asInstanceOf[Input]: Input): Input #unchecked) match {
case (defaultCase$ # _) => {
scala.Predef.println("xxx");
input.inner match {
case (innerA # (_: InnerA)) => {
val id: String = (input: A1 #unchecked) match {
case (id: String, inner: Inner): Input((id # _), _) => id
};
Output.apply(id, innerA)
}
}
}
case (defaultCase$ # _) => default.apply(input)
};
final def isDefinedAt(input: Input): Boolean = ((input.asInstanceOf[Input]: Input): Input #unchecked) match {
case (defaultCase$ # _) => true
case (defaultCase$ # _) => false
}
In this case, you're creating a PartialFunction[Input, Output] that is defined for all intervals of Input, and this is fine. But when the compiler checks the inner input.inner match, it warns you that this match - not the first one - is not exhaustive.
this partial function pf doesn't blow up with a MatchError when inner is not InnerA
If you call it directly with such an argument
pf(Input("a", InnerB("b", 0)))
you do get a MatchError; but the whole point of PartialFunction is to provide additional information in isDefinedAt, and collect uses it by not calling pf where isDefinedAt returns false.
Is this quirk documented somewhere?
See paragraph 6.23.1 Translation of specification:
When a PartialFunction is required, an additional member isDefinedAt is synthesized, which simply returns true. However, if the function literal has the shape x => x match { … }, then isDefinedAt is derived from the pattern match in the following way: each case from the match expression evaluates to true, and if there is no default case, a default case is added that evaluates to false.
So for your second version isDefinedAt is always true; the first one doesn't exactly fit x => x match..., but apparently it's supported too. Now the usual way to define a PartialFunction is like Luis Miguel Mejía Suárez's comment says
{ case Input(id, InnerA(name)) => Output(id, InnerA(name)) }
but it simply gets translated into
x => x match { case Input(id, InnerA(name)) => Output(id, InnerA(name)) }

How do I call a method that only exists on one of the 2 types in an Either?

I have an array of objects of type Either[A, B]. If I know for a particular element whether it is an A or a B, how do I call a method on it that only exists on one of the 2 types. For example:
import scala.util.Random
object EitherTest extends App {
def newObj(x: Int): Either[A,B] = {
if (x == 0)
Left(new A())
else
Right(new B())
}
val random = new Random()
val randomArray = (0 until 10).map(_ => random.nextInt(2))
val eitherArray = randomArray.map(newObj)
(0 until 10).foreach(x => randomArray(x) match {
case 0 => eitherArray(x).aMethod()
case 1 => eitherArray(x).bMethod()
case _ => println("Error!")
})
}
class A {
def aMethod() = println("A")
}
class B {
def bMethod() = println("B")
}
When I compile this code, the lines
case 0 => eitherArray(x).aMethod()
case 1 => eitherArray(x).bMethod()
both have the error "value aMethod is not a member of Either[A,B]". How can I solve this?
I don't know why fold doesn't get the respect it deserves. It can be so useful.
eitherArray.foreach(_.fold(_.aMethod(), _.bMethod()))
Well, you can do it if you exctract the logic to another method, and do some pattern matching over the value Either, then check if it is Right or Left, and that's it!
object HelloWorld {
import scala.util.Random
def main(args: Array[String]) {
val random = new Random()
val randomArray = (0 until 10).map(_ => random.nextInt(2))
val eitherArray = randomArray.map(EitherTest.newObj)
(0 until 10).foreach(x => randomArray(x) match {
case 0 => EitherTest.callmethod(eitherArray(x))
case 1 => EitherTest.callmethod(eitherArray(x))
case _ => println("Error!")
})
println("Hello, world!")
}
}
class EitherTest
object EitherTest {
def callmethod(ei : Either[A,B]) = {
ei match {
case Left(a) => a.aMethod()
case Right(b) => b.bMethod()
}
}
def newObj(x: Int): Either[A,B] = {
if (x == 0)
Left(new A())
else
Right(new B())
}
}
class A {
def aMethod() = println("A")
}
class B {
def bMethod() = println("B")
}
Will print for you, for one random example:
A
B
A
B
A
A
A
B
B
B
Hello, world!
Basically, the way you do with Either is projections: Either.left gives you the projection of the left type, and Either.right gives you that of the right.
The projections are somewhat similar to options, in that they can be empty (if your Either is a Right, then the left projection is empty and vice versa), and you can use the usual monadic transformations with them, like map, flatMap, foreach, getOrElse etc.
Your example, could look like this:
randomArray.foreach { either =>
either.left.foreach(_.aMethod)
either.right.foreach(_.bMethod)
}
You could also use pattern-matching instead, that's less general, but, perhaps looks a bit clearer in this case:
randomArray.foreach {
case Left(a) => a.aMethod
case Right(b) => b.bMethod
}

Can we have an array of by-name-parameter functions?

In Scala we have a by-name-parameters where we can write
def foo[T](f: => T):T = {
f // invokes f
}
// use as:
foo(println("hello"))
I now want to do the same with an array of methods, that is I want to use them as:
def foo[T](f:Array[ => T]):T = { // does not work
f(0) // invokes f(0) // does not work
}
foo(println("hi"), println("hello")) // does not work
Is there any way to do what I want? The best I have come up with is:
def foo[T](f:() => T *):T = {
f(0)() // invokes f(0)
}
// use as:
foo(() => println("hi"), () => println("hello"))
or
def foo[T](f:Array[() => T]):T = {
f(0)() // invokes f(0)
}
// use as:
foo(Array(() => println("hi"), () => println("hello")))
EDIT: The proposed SIP-24 is not very useful as pointed out by Seth Tisue in a comment to this answer.
An example where this will be problematic is the following code of a utility function trycatch:
type unitToT[T] = ()=>T
def trycatch[T](list:unitToT[T] *):T = list.size match {
case i if i > 1 =>
try list.head()
catch { case t:Any => trycatch(list.tail: _*) }
case 1 => list(0)()
case _ => throw new Exception("call list must be non-empty")
}
Here trycatch takes a list of methods of type ()=>T and applies each element successively until it succeeds or the end is reached.
Now suppose I have two methods:
def getYahooRate(currencyA:String, currencyB:String):Double = ???
and
def getGoogleRate(currencyA:String, currencyB:String):Double = ???
that convert one unit of currencyA to currencyB and output Double.
I use trycatch as:
val usdEuroRate = trycatch(() => getYahooRate("USD", "EUR"),
() => getGoogleRate("USD", "EUR"))
I would have preferred:
val usdEuroRate = trycatch(getYahooRate("USD", "EUR"),
getGoogleRate("USD", "EUR")) // does not work
In the example above, I would like getGoogleRate("USD", "EUR") to be invoked only if getYahooRate("USD", "EUR") throws an exception. This is not the intended behavior of SIP-24.
Here is a solution, although with a few restrictions compared to direct call-by-name:
import scala.util.control.NonFatal
object Main extends App {
implicit class Attempt[+A](f: => A) {
def apply(): A = f
}
def tryCatch[T](attempts: Attempt[T]*): T = attempts.toList match {
case a :: b :: rest =>
try a()
catch {
case NonFatal(e) =>
tryCatch(b :: rest: _*)
}
case a :: Nil =>
a()
case Nil => throw new Exception("call list must be non-empty")
}
def a = println("Hi")
def b: Unit = sys.error("one")
def c = println("bye")
tryCatch(a, b, c)
def d: Int = sys.error("two")
def e = { println("here"); 45 }
def f = println("not here")
val result = tryCatch(d, e, f)
println("Result is " + result)
}
The restrictions are:
Using a block as an argument won't work; only the last expression of the block will be wrapped in an Attempt.
If the expression is of type Nothing (e.g., if b and d weren't annotated), the conversion to Attempt is not inserted since Nothing is a subtype of every type, including Attempt. Presumably the same would apply for an expression of type Null.
As of Scala 2.11.7, the answer is no. However, there is SIP-24, so in some future version your f: => T* version may be possible.

Scala recursive macro?

I was wondering whether Scala supports recursive macro expansion e.g. I am trying to write a lens library with a lensing macro that does this:
case class C(d: Int)
case class B(c: C)
case class A(b: B)
val a = A(B(C(10))
val aa = lens(a)(_.b.c.d)(_ + 12)
assert(aa.b.c.d == 22)
Given lens(a)(_.b.c.d)(f), I want to transforms it to a.copy(b = lens(a.b)(_.c.d)(f))
EDIT:
I made some decent progress here
However, I cannot figure out a generic way to create an accessor out of List[TermName] e.g. for the above example, given that I have List(TermName('b'), TermName('c'), TermName('d'))), I want to generate an anonymous function _.b.c.d i.e. (x: A) => x.b.c.d. How do I do that?
Basically, how can I write these lines in a generic fashion?
Actually I managed to make it work: https://github.com/pathikrit/sauron/blob/master/src/main/scala/com/github/pathikrit/sauron/package.scala
Here is the complete source:
package com.github.pathikrit
import scala.reflect.macros.blackbox
package object sauron {
def lens[A, B](obj: A)(path: A => B)(modifier: B => B): A = macro lensImpl[A, B]
def lensImpl[A, B](c: blackbox.Context)(obj: c.Expr[A])(path: c.Expr[A => B])(modifier: c.Expr[B => B]): c.Tree = {
import c.universe._
def split(accessor: c.Tree): List[c.TermName] = accessor match { // (_.p.q.r) -> List(p, q, r)
case q"$pq.$r" => split(pq) :+ r
case _: Ident => Nil
case _ => c.abort(c.enclosingPosition, s"Unsupported path element: $accessor")
}
def join(pathTerms: List[TermName]): c.Tree = (q"(x => x)" /: pathTerms) { // List(p, q, r) -> (_.p.q.r)
case (q"($arg) => $pq", r) => q"($arg) => $pq.$r"
}
path.tree match {
case q"($_) => $accessor" => split(accessor) match {
case p :: ps => q"$obj.copy($p = lens($obj.$p)(${join(ps)})($modifier))" // lens(a)(_.b.c)(f) = a.copy(b = lens(a.b)(_.c)(f))
case Nil => q"$modifier($obj)" // lens(x)(_)(f) = f(x)
}
case _ => c.abort(c.enclosingPosition, s"Path must have shape: _.a.b.c.(...), got: ${path.tree}")
}
}
}
And, yes, Scala does apply the same macro recursively.