コンパイル時にズンドコする。それが型レベルズンドコキヨシ。
型だけでランダムにする方法があるらしいですがよく分からないのであきらめてマクロ使ってしまいました。だれかお願いします。 書いてくれました。
コード
まずランダムにズンかドコを決めるため、2つの型をとってどっちか返すみたいなマクロを用意。
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
trait Which[A, B] {
type Out
}
object Which {
type Aux[A, B, C] = Which[A, B] {type Out = C}
def randImpl[A: c.WeakTypeTag, B: c.WeakTypeTag](c: Context): c.Tree = {
import c.universe._
val tpeA = weakTypeOf[A]
val tpeB = weakTypeOf[B]
val tpeC = if (scala.util.Random.nextBoolean) tpeA else tpeB
q"new Which[$tpeA, $tpeB] { type Out = $tpeC }: Which.Aux[$tpeA, $tpeB, $tpeC]"
}
implicit def which[A, B, C]: Which.Aux[A, B, C] = macro randImpl[A, B]
}
ズンかドコをWhichで取得して、その結果をHListにためていきます。例の文言になったらキヨシを付けて返すだけです。
import shapeless._
import shapeless.ops.hlist.Reverse
object Main extends App {
trait ズン
trait ドコ
trait `キ・ヨ・シ!`
implicit case object ズン extends ズン
implicit case object ドコ extends ドコ
case object `キ・ヨ・シ!` extends `キ・ヨ・シ!`
trait Kiyoshi[A <: HList] {
type Out <: HList
def apply(a: A): Out
}
object Kiyoshi extends LowPriority {
implicit def k0[L <: HList](implicit r: Reverse[`キ・ヨ・シ!` :: ドコ :: ズン :: ズン :: ズン :: ズン :: L]) = new Kiyoshi[ドコ :: ズン :: ズン :: ズン :: ズン :: L] {
type Out = r.Out
def apply(l: ドコ :: ズン :: ズン :: ズン :: ズン :: L) = r(`キ・ヨ・シ!` :: l)
}
}
trait LowPriority {
implicit def k1[A, L <: HList](implicit w: Which.Aux[ズン, ドコ, A], a: A, k: Lazy[Kiyoshi[A :: L]]) = {
new Kiyoshi[L] {
type Out = k.value.Out
def apply(l: L) = k.value(a :: l)
}
}
}
println(the[Kiyoshi[HNil]].apply(HNil: HNil))
}
実行
> run
[info] Compiling 1 Scala source to /Volumes/USB1/Documents/my/macro-sample/core/target/scala-2.11/classes...
[info] Running Main
ズン :: ドコ :: ズン :: ドコ :: ズン :: ズン :: ドコ :: ズン :: ドコ :: ズン :: ズン :: ドコ :: ズン :: ズン :: ズン :: ズン :: ドコ :: キ・ヨ・シ! :: HNil
[success] Total time: 4 s, completed 2016/03/28 21:14:53
再コンパイルしない限り同じものを出力。
> run
[info] Running Main
ズン :: ドコ :: ズン :: ドコ :: ズン :: ズン :: ドコ :: ズン :: ドコ :: ズン :: ズン :: ドコ :: ズン :: ズン :: ズン :: ズン :: ドコ :: キ・ヨ・シ! :: HNil
[success] Total time: 0 s, completed 2016/03/28 21:15:51
再度コンパイルすると結果が変わります。
> run
[info] Compiling 1 Scala source to /Volumes/USB1/Documents/my/macro-sample/core/target/scala-2.11/classes...
[info] Running Main
ドコ :: ズン :: ズン :: ズン :: ドコ :: ドコ :: ドコ :: ドコ :: ドコ :: ドコ :: ズン :: ドコ :: ズン :: ドコ :: ズン :: ズン :: ズン :: ドコ :: ドコ :: ズン :: ドコ :: ズン :: ズン :: ズン :: ドコ :: ドコ :: ドコ :: ズン :: ドコ :: ズン :: ズン :: ズン :: ドコ :: ズン :: ズン :: ズン :: ドコ :: ドコ :: ズン :: ズン :: ズン :: ズン :: ドコ :: キ・ヨ・シ! :: HNil
[success] Total time: 3 s, completed 2016/03/28 21:16:54