DottyのMatch Typeを使ってコンパイル時にFibonacciを計算する

見た目通りで、あまり難しくないので、特に説明することがない。 macroさえ使わずに書けますね。 shapelessにあったような色々な機能が標準で装備されています。

みなさん、Match Type使ってもっと複雑な色々な計算書いてみましょう。

ちなみに、この単純な実装だと、大きい数渡すと(コンパイル時に)大変なことになるのでご注意ください。

plugins.sbt

addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.4.1")

build.sbt

scalaVersion := "0.26.0-RC1"

Main.scala

package example

import scala.compiletime.ops.int.{-, +}
import scala.compiletime.testing.{typeChecks, typeCheckErrors, Error, ErrorKind}

type Fibonacci[A <: Int] <: Int =
  A match {
    case 0 => 0
    case 1 => 1
    case _ => Fibonacci[A - 1] + Fibonacci[A - 2]
  }

object Main {
  def main(args: Array[String]): Unit = {
    val _: Fibonacci[10] = 55 // success. compile fail if other value
    
    assert(typeChecks("val _: Fibonacci[10] = 55"))
    assert(typeChecks("val _: Fibonacci[10] = 4") == false)
    val result = typeCheckErrors("val _: Fibonacci[10] = 4")
    println(result)
    assert(
      result == List(
        Error(
          message = "Found:    (4 : Int)\nRequired: (55 : Int)",
          lineContent = "val _: Fibonacci[10] = 4",
          column = 23,
          kind = ErrorKind.Typer
        )
      )
    )
  }
}

あと、上記の定義があった場合に、こういうのを定義することも可能です。

transparent inline def fibonacci[A <: Int]: Fibonacci[A] =
  valueOf[Fibonacci[A]]
  • transparent inlineは、Scala 2のwhitebox macroみたいにコンパイル時に、指定した戻り型のsub type返せるやつ
  • valueOfはScala 2.13にもある、その型の値を返せるやつ(Scala 2.13でも valueOf[3] とか出来る)

その他詳細は以下を見てください