0Pricing
Scala for Backend Engineering & Functional Programming · レッスン

Quotes と Splices

コードをデータとして扱います。

「Quotes と Splices」はCoddyKit上の無料Scala for Backend Engineering & Functional Programmingレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはScala for Backend Engineering & Functional Programming学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Scala for Backend Engineering & Functional Programmingコースには全4レッスンが含まれています。

コードをデータとして扱う

Scala 3のメタプログラミングでは、コードをデータとして扱います。クォートはコードの一部をExprとして取得し、スプライスはExprをコードに戻して挿入します。

クォート: '{ ... }

'{ expr }は式をExpr[T]に変換します。コードは実行されず、マクロが操作できる値になります。

import scala.quoted.*

def greeting(using Quotes): Expr[String] = '{ "Hello, " + "world" }

スプライス: ${ ... }

${ expr }はExprを外側のクォートに挿入し、生成された断片をつなぎ合わせます。クォートとスプライスは逆の操作です。

import scala.quoted.*

def doubled(x: Expr[Int])(using Quotes): Expr[Int] = '{ ${ x } * 2 }

リフトした値のスプライス

クォートの内部では、Expr(...)でリフトした値をスプライスして、コンパイル時定数を生成コードに埋め込めます。

import scala.quoted.*

def addN(x: Expr[Int], n: Int)(using Quotes): Expr[Int] =
  '{ ${ x } + ${ Expr(n) } }

コードを再帰的に構築する

マクロは、ループや再帰の中でクォートとスプライスを組み合わせ、複雑な式を構築します。たとえば、べき乗を繰り返しの乗算へ展開できます。

import scala.quoted.*

def pow(x: Expr[Double], n: Int)(using Quotes): Expr[Double] =
  if (n == 0) '{ 1.0 } else '{ ${ x } * ${ pow(x, n - 1) } }

クォートのパターンマッチング

クォートのパターンにマッチさせることで、コードを分解できます。これにより式の形状を調べ、最適化や書き換えを行えます。

import scala.quoted.*

def optimize(e: Expr[Int])(using Quotes): Expr[Int] = e match {
  case '{ ($a: Int) + 0 } => a
  case _                  => e
}

Type[T]とクォートされた型

Expr[T]が式を保持するのと同様に、Type[T]は型を保持します。'[T]で型をクォートし、型が必要な場所ではgiven Type[T]を使ってスプライスします。

import scala.quoted.*

def typeName[T](using t: Type[T], q: Quotes): Expr[String] =
  Expr(Type.show[T])

reflect API

より低レベルな処理では、quotes.reflectが抽象構文木(Term、Symbol、TypeRepr)を公開します。これにより、クォートだけでは直接表現できないコードも調査・構築できます。

import scala.quoted.*

def show(e: Expr[Any])(using q: Quotes): Expr[String] = {
  import q.reflect.*
  Expr(e.asTerm.show)
}

レベル間の往復変換

asTermでExprをTermに変換し、asExpr / asExprOf[T]で戻せます。これにより、高レベルのクォートAPIとリフレクションAPIを橋渡しできます。

import scala.quoted.*

def ident[T: Type](e: Expr[T])(using q: Quotes): Expr[T] = {
  import q.reflect.*
  e.asTerm.asExprOf[T]
}

実行時の例

先ほどの再帰的なべき乗マクロは、通常の乗算へ展開されます。この自己完結型の実行時バージョンは、生成されたコードが返す結果と同じ結果を示します。

object Main {
  def pow(x: Double, n: Int): Double =
    if (n == 0) 1.0 else x * pow(x, n - 1)
  def main(args: Array[String]): Unit = {
    println(pow(3.0, 2)) // 9.0
  }
}

クォートとスプライスは逆の操作

この双対性を覚えておきましょう。'{ }はコードをExprへ持ち上げ、${ }はExprをコードに戻します。これらを正しく入れ子にすることが、マクロ構築の核心です。

確認問題

クォートの内部でスプライス演算子${ x }は何をしますか?

まとめ

クォートとスプライスについて学びました。

  • '{ }はコードをExpr[T]にクォートします
  • ${ }はExprをコードにスプライスします
  • クォートのパターンマッチングでコードを分解します
  • Type[T]とreflect API

次は、実践的なマクロです。

よくある質問

「Quotes と Splices」レッスンは無料ですか?

はい。「Quotes と Splices」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Scala for Backend Engineering & Functional Programmingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Scala for Backend Engineering & Functional Programmingコースには全4レッスンが含まれています。

「Quotes と Splices」で何を学びますか?

コードをデータとして扱います。 ブラウザで直接実行するハンズオンコードでScala for Backend Engineering & Functional Programmingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Scala for Backend Engineering & Functional Programmingを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのScala for Backend Engineering & Functional Programmingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「Quotes と Splices」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このScala for Backend Engineering & Functional Programmingレッスンでコードを書いて実行できますか?

はい。すべてのScala for Backend Engineering & Functional Programmingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. インラインメソッド
  2. マクロの基礎
  3. Quotes と Splices
  4. 実践的なマクロ
← Scala for Backend Engineering & Functional Programmingに戻る