2013-03-06 22 views
5

作为对this question的回应,我一直在使用宏天堂分支在Scala中实现Haskell风格的'where'表达式。代码可在scala-where获得。现在我可以写类似如下:Scala无类宏在中缀位置

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

不过,我真正想要做的是能在缀的位置称之为:

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

通常情况下,这样的事情会很容易,但我不明白如何通过宏调用来实现。表达式(f1(1)* f2(2))在宏应用程序之前不会键入,因此类似构建隐式值类不起作用。有没有办法得到这种语法呢?

如果做不到这一点,只是有两个参数列表,这样一个可以这样做:

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

将是很好的,但这又似乎很难。我们可以用两个参数列表调用宏吗?

回答

2

对于第一个选择:我认为你可以使隐式转换成为一个无类型的宏本身,不是吗?

对于第二个选项:您可以使用多个参数列表调用宏,是的。在调用点多名单将在定义站点翻译成多个列表,如:

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

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

将被称为:

myMacro(...)(...) 
+1

两个参数列表的是伟大的,谢谢!我不知怎的错过了。 – Impredicative 2013-03-07 09:26:38

+1

关于隐式转换 - 我不知道如何挂钩到宏系统。我不认为这可能是一个隐式转换,因为肯定必须键入该树才能搜索转换? – Impredicative 2013-03-07 09:28:07

+0

你可能是对的,虽然我认为你可以做'implicit def conv = macro conv_impl; def conv_impl(c:Context)(x:c.Tree):c.Expr [T]'并且基本上是类型'Any => T' – 2013-03-07 18:48:47

1

答:截至2013年3月8日是不可能的在中缀位置使用无类型宏。从尤金Burmako上引scala-user mailing list

目前左边的参数必须是之前 中,你可以写的事实“类 FOO(X:__)”任何隐含的分辨率踢第一typechecked。是一个疏忽 - 下划线语法应该是 只能在无类型的宏中工作。

仅供参考,我来到了能做到这一点,最近是以下几点:

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 : _*) 
}