Estou construindo uma DSL usando o scala, que filtrará os dados com base nas condições de uma DSL.
Função do filtro:
def filter(f: (Int) => (Int)) {
// find what is the name (age) of lambda passed
// query db with column name age and apply function f and return value
}
Usando no DSL, como:
filter( (age) => age > 10 )
Não consigo encontrar uma maneira de saber isso no DSL age
é usado, existe uma maneira?
Por enquanto, estou passando a string como primeiro argumento, como abaixo:
filter( "age", (age) => age > 10 )
e alterou o filtro para receber o primeiro argumento como nome da coluna.
Eu quero simplificar o DSL.
Respostas:
3 para resposta № 1Atualmente, a única maneira de obter um nome do argumento da instância lambda é declarando uma macro Scala em vez de um método Scala para filter
. Uma macro receberá a árvore de sintaxe abstrata do lambda, em vez do próprio lambda, para poder analisar o nome dos argumentos do lambda.
Aqui está um exemplo muito mínimo de como fazer isso:
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
object MyFilter {
def filter(p: Int => Int): Unit = macro filterImpl
def filterImpl(c: Context)(p: c.Expr[Int => Int]): c.Expr[Unit] = {
import c.universe._
val Function(args, body) = p.tree
val ValDef(mods, name, tp, rhs) = args(0)
println(name)
reify {
()
}
}
}
Acima, primeiro importamos os pacotes relevantes para ativar as macros. Então, definimos o macro def filter
juntamente com sua implementação filterImpl
. Finalmente, implementamos a macro - padronizamos a correspondência da árvore do argumento em uma Function
árvore, então pegue o primeiro argumento (args(0)
) e, finalmente, o padrão corresponde ao primeiro argumento em um ValDef
árvore para poder extrair o nome.
Você pode ler mais sobre macros Aqui.