LoginSignup
1
1

More than 1 year has passed since last update.

関数をパラメータオブジェクトに対応させるためのマクロ

Last updated at Posted at 2015-07-28

を書いた。

#サンプル

以下のように関数を定義すると

import x7c1.salad.parameter.Agglomerator.define

def show = define { (id: Int, name: String) =>
  s"id:$id, name:$name"
}

二通りの方法で引数を渡すことができるようになる。

一つはいつもどおりの形。

show(123, "foo")//id:123, name:foo

もう一つは構造的部分型を利用した形。

case class User(id: Int, name: String, nick: String)
val user = User(
  id = 123,
  name = "foo",
  nick = "bar"
)
show(user)//id:123, name:foo

これで委譲するためだけの同じような関数を書く手間は不要になった。

##補足

引数の名前と型さえ一致していれば任意のオブジェクトを渡すことができる。

case class Address(id: Int, name: String, postal: String)
val address = Address(
  id = 123,
  name = "foo",
  postal = "bar"
)
println(show(address))// id:123, name:foo

もちろん引数を満たしていなければコンパイル時に検出される。

case class Anonym(id: Int)
val anon = Anonym(id = 123)
println(show(anon))

//type mismatch;
//[error]  required: Object{def id: Int; def name: String}
//[error]  println(show(anon))
//[error]               ^
//[error] one error found

#利用方法

lazy val `your-app` = project.
  dependsOn(ProjectRef(uri("git://github.com/x7c1/Salad.git#0.4.0"), "salad-lib"))

#中身

object Agglomerator {
  def define[A](f: A): Any = macro AgglomeratorImpl.define[A]
}
private object AgglomeratorImpl {
  def define[A: c.WeakTypeTag](c: whitebox.Context)(f: c.Expr[A]) = {
    import c.universe._

    val args = f.tree.children.filter(_.isDef)
    val names = args.map(_.symbol.asTerm.name)

    val fields = args.map{ x =>
      q"def ${x.symbol.asTerm.name}: ${x.symbol.typeSignature}"
    }
    val A = TypeName(c.freshName())
    val arg = TermName(c.freshName())
    val access: TermName => Tree = key => q"$arg.$key"

    q"""
      new {
        type $A = { ..$fields }
        def apply($arg: $A) = $f(..${names map access})
        def apply(..$args) = $f(..$names)
      }
    """
  }
}

#参考 : パラメータオブジェクトについて

#参考 : Scala のマクロについて

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1