Created
March 6, 2013 19:52
-
-
Save travisbrown/5102474 to your computer and use it in GitHub Desktop.
Creating single abstract method class instances from function literals in Scala.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scala.language.experimental.macros | |
import scala.language.higherKinds | |
import scala.reflect.macros.Context | |
object MacroSAM { | |
def sam[F[_, _], A, B](f: A => B) = macro sam_impl[F, A, B] | |
def sam_impl[F[_, _], A: c.WeakTypeTag, B: c.WeakTypeTag](c: Context) | |
(f: c.Expr[A => B])(implicit tag: c.WeakTypeTag[F[_, _]]) = { | |
import c.universe._ | |
val anon = newTypeName(c.fresh()) | |
val fab = appliedType(tag.tpe, List(weakTypeOf[A], weakTypeOf[B])) | |
c.Expr[F[A, B]](f.tree match { | |
case Function(valDef :: Nil, body) => Block( | |
ClassDef( | |
Modifiers(Flag.FINAL), | |
anon, | |
Nil, | |
Template( | |
TypeTree(fab) :: Nil, | |
emptyValDef, | |
List( | |
constructor(c), | |
DefDef( | |
Modifiers(), | |
newTermName("apply"), | |
Nil, | |
List(valDef :: Nil), | |
TypeTree(), | |
c.resetAllAttrs(body) | |
) | |
) | |
) | |
), | |
Apply(Select(New(Ident(anon)), nme.CONSTRUCTOR), Nil) | |
) | |
}) | |
} | |
def constructor(c: Context) = { | |
import c.universe._ | |
DefDef( | |
Modifiers(), | |
nme.CONSTRUCTOR, | |
Nil, | |
Nil :: Nil, | |
TypeTree(), | |
Block( | |
Apply( | |
Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), | |
Nil | |
) :: Nil, | |
c.literalUnit.tree | |
) | |
) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import MacroSAM.sam | |
trait MyFunc[-A, +B] { | |
def apply(a: A): B | |
} | |
object MyFuncExample { | |
def main(args: Array[String]) { | |
val x = sam[MyFunc, Int, Int] { a: Int => a } | |
println(x) | |
println(x(42)) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You'd need an implicit conversion from
A => B
toF[A, B]
for that. However, I suspect that this is problematic – under some circumstances, scalac is not able to infer whatF
is supposed to be (i.e. it infersNothing
instead ofMyFunc
).