Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala untyped macro in infix position

In response to this question, I've been having a go at implementing a Haskell-style 'where' expression in Scala using the macro-paradise branch. The code is available at scala-where. I can now write something like the following:

val result = where ( f1(1) * f2(2), {
  def f1(x : Int) = x + 1
  def f2(x : Int) = x + 2
})

However, what I'd really like to do is to be able to call this in infix position:

val result = ( f1(1) * f2(2)) where {
  def f1(x : Int) = x + 1
  def f2(x : Int) = x + 2
}

Normally, this sort of thing would be easy, but I can't see how to do it with the macro call. The expression (f1(1) * f2(2)) won't type before macro application, so something like building an implicit value class doesn't work. Is there a way to get this kind of syntax otherwise?

Failing this, just having two parameter lists so one could do:

val result = where (f1(1) * f2(2)) {
  def f1(x : Int) = x + 1
  def f2(x : Int) = x + 2
}

would be nice, but again this seems difficult. Can one call a macro with two parameter lists?

like image 977
Impredicative Avatar asked Oct 22 '22 15:10

Impredicative


2 Answers

For the first option: I would think you could make the implicit conversion an untyped macro itself, no?

For the second option: You can call a macro with multiple parameter lists, yes. Multiple lists at the call site will translate to multiple lists at the definition site, e.g.:

def myMacro(a: _)(b: _) = macro myMacro_impl

def myMacro_impl(c: Context)(a: c.Tree)(b: c.Tree): c.Tree = { ... }

Would be called as:

myMacro(...)(...)
like image 115
Ptharien's Flame Avatar answered Nov 15 '22 06:11

Ptharien's Flame


Answer: as of 2013-03-08 it is not possible to use untyped macros in an infix position. Quoted from Eugene Burmako on the scala-user mailing list:

Currently the argument on the left has to be typechecked first before any implicit resolution kicks in. The fact that you can write "class foo(x: _)" is an oversight - the underscore syntax is supposed to be working only in untyped macros.

For reference, the closest I came to being able to do this was the following:

implicit class HasWhere(val exp : _) {
 def where(block : Unit) = macro whereInfix
}

def whereInfix(c : Context)(block : c.Expr[Unit]) = {
  import c.universe._

  val exp = Select(c.prefix.tree, TermName("exp"))
  val Expr(Block((inner, _))) = block
  val newinner = inner :+ exp
  Block(newinner : _*)
}
like image 26
Impredicative Avatar answered Nov 15 '22 07:11

Impredicative