LoginSignup
15
13

More than 5 years have passed since last update.

型レベルズンドコキヨシ with Scala

Last updated at Posted at 2016-03-27

コンパイル時にズンドコする。それが型レベルズンドコキヨシ。

型だけでランダムにする方法があるらしいですがよく分からないのであきらめてマクロ使ってしまいました。だれかお願いします。 書いてくれました。

コード

まずランダムにズンかドコを決めるため、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
15
13
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
15
13