2013-03-06 66 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 : _*) 
}