Skip to content

Instantly share code, notes, and snippets.

View stanch's full-sized avatar

Nick stanch

  • Product Manager at @snowplow
  • Lisbon, Portugal
View GitHub Profile
// deep search inside myLayout
myLayout ~~> {
// make all buttons have medium-sized text
case b: Button ⇒ b ~> TextSize.medium
// find layouts consisting of just ImageView and TextView
case Layout(m: ImageView, t: TextView) ⇒
t ~> text("I’m next to an image")
// hide everything else
case otherStuff ⇒ otherStuff ~> hide
}
[info] [running phase parser on 9 compilation units]
[info] [running phase macroparadise on 9 compilation units]
[info] [running phase namer on 9 compilation units]
[info] [running phase packageobjects on 9 compilation units]
[info] [running phase typer on 9 compilation units]
[warn] issue error: type mismatch;
[warn] found : c.WeakTypeTag[X&0]
[warn] (which expands to) c.universe.WeakTypeTag[X&0]
[warn] required: c.universe.WeakTypeTag[needs.this.Need[_$1] forSome { type _$1 }]
[warn] issue error: type mismatch;
new SVerticalLayout {
STextView("ID")
val userId = SEditText()
SButton("Sign in", signin(userId.text))
}.padding(20 dip)
var userId = slot[EditText]
l[VerticalLinearLayout](
w[TextView] ~> text("ID"),
w[EditText] ~> wire(userId),
w[Button] ~> text("Sign in") ~> On.click(signin(userId.get.getText))
) ~> padding(all = 20 dp)
def largeText(t: String)(implicit ctx: Context) = text(t) + TextSize.large
// use with Options:
var maybeTweak: Option[Tweak[TextView]] = Some(text("Hi"))
myTextView ~> maybeTweak // this will set the text
maybeTweak = None
myTextView ~> maybeTweak // this will be ignored
// use with Futures:
val showInASecond = future {
Thread.sleep(1000)
show
Future {
// perform something in background
val url = ...
val data = fetch(url)
process(data)
} mapUi { data ⇒
// this will happen on the UI thread
display(data)
} onFailureUi {
// handle failure on the UI thread

The problem

Sometimes it is useful to be able to explore the parent AST in a macro. Examples include guiding type inference, building tree-like DSLs, etc (see below). Unfortunately, the current macro API makes it extremely awkward (also see below). Here I propose a way to separate such functionality in a well-defined (safe, optimized) new type of macros and leverage existing Scala features (traits + implicits) to take care of the rest.

Motivating example 1

import scala.language.higherKinds
import play.api.libs.functional._
import shapeless._
import shapeless.ops.hlist.RightFolder
import play.api.data.mapping.{ From, Reader, Rule }
import play.api.libs.json.{Json, JsValue}
import play.api.data.mapping.json.Rules._
object applicativeFolder2 extends Poly2 {
// Rule[I, X] :: Rule[I, L] -> Rule[I, X :: L]
// F[A] :: F[B] :: ... :: M :: F[N] :: O :: ... :: HNil -> F[A :: B :: ... :: M :: N :: O :: ... :: HNil]
object applicativeFolder extends Poly2 {
// (F[A], F[B]) -> F[A :: B]
implicit def caseApp[A, B <: HList, F[_]](implicit app: Applicative[F]) =
at[F[A], F[B]] { (a, b) ⇒
app.apply[A, A :: B](app.map[B, A ⇒ A :: B](b, x ⇒ y ⇒ y :: x), a)
}
// (A, F[B]) -> F[A :: B] (uses Applicative.pure)
implicit def casePure[A, B <: HList, F[_]](implicit app: Applicative[F], pure: A <:!< F[_]) =