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
val rx1 = Var(1)
val rx2 = Var(2)
val rx3 = Rx { rx1() + rx2() }
// ...
val style = TextSize.large + padding(all = 16 dp)
def rxText(rx: Rx[Int]) = rx.map(_.toString).map(text)
import org.scalajs.dom
import scalatags.HtmlTag
import scalatags.all._
import scalatags._
@JSExport
object ScalaJSExample {
@JSExport
def main(args: Array[String]) = {
/* "a123b45c" → ["a", 123, "b", 45, "c"] */
function nat(x) {
// digit-parts
var d = x.split(/[^0-9]+/); // ["", "123", "45, ""]
// alpha-parts
var a = x.split(/[0-9]+/); // ["a", "b", "c"]
// helpers
function nonEmpty(x) { return x != "" }
function toInt(x) { return x - 0 }
// the one that does not start with a "" goes first
// 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[_]) =
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]

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

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
// 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
def largeText(t: String)(implicit ctx: Context) = text(t) + TextSize.large
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)