Scala 3ã®ãã¯ãTips 100é£çº
ãã®è¨äºã¯Scala Advent Calendar 2023ã®12æ¥ç®ã !
Scala 3ã®ãã¯ããæ¸ãä¸ã§å½¹ã«ç«ã¤, ã¡ã¿ããTipsãã¡ãç´¹ä»ããã! å¢ãã«ä»»ãã¦æ¸ãã¦ãããããµã³ãã«ã³ã¼ããã¡ããã¨åããªãã£ããããããª. ä¸å¿, Scala 3.3.1ãæ³å®ãã¦ããã.
- ãã¯ã
- 1. ã¡ã½ããããã¯ãã¨ãã¦å®ç¾©ãã
- 2. ãã¯ãã®æ¬ä½ãå®è£ ãã
- 3. ãã¯ãå®è£ ã®è¨æ³ã®æå³ãç¥ã
- 4. ãã¯ãã§çæãããã³ã¼ãã®å 容ã確èªãã
- 5. å¼æ°ã®å¼ãè©ä¾¡ããã«ä½¿ã
- 6. è¿ãå¤ã®åããã¯ãã®å®è¡çµæã«ãã£ã¦æ±ºãã
- 7. ãã¯ãã®è¿ãå¤ã®åãå¶éãã
- 8. ãã¯ãã®è¿ãå¤ã®åãæ¸ããªã
- 9. ãã¯ãã§è¨ç®ãããåããã¹ããã
- 10. ãã¯ãã§è¨ç®ãããåãScalaTestã§ãã¹ããã
- å¼
- 11. å®æ°å¼ã®å¤ãå¾ã
- 12. å®æ°å¼ã§ãªããã°ã³ã³ãã¤ã«ã¨ã©ã¼ã«ãã
- 13. å®æ°å¤ã®å¼ãä½ã
- 14. ã³ã¼ããçæãã
- 15. çæã³ã¼ãã®ä¸ã«è¨ç®ãããå¤ãåãè¾¼ã
- 16. å¼ããã¿ã¼ã³ããããã
- 17. å¼ãã¿ãã«ã«ãã¿ã¼ã³ããããã
- 18. å¼ã®ãã¿ã¼ã³ãããã§ä¸è¦ãªå¤æ°ãæç¸ããªã
- 19. å¼ã®ã³ã³ãã¤ã«æã®åãå¾ã
- 20. å¼ãå°åãã
- å
- å¼ã®æ½è±¡æ§ææ¨
- åã®æ½è±¡æ§ææ¨
- 30. åã®æ½è±¡æ§ææ¨ãå¾ã
- 31. åãçãå°åãã
- 32. Typeããæ½è±¡æ§ææ¨ãå¾ã
- 33. ãªãã©ã«åã®æ½è±¡æ§ææ¨ãä½ã
- 34. åã®æ§é ãå°åãã
- 35. åã®æ½è±¡æ§ææ¨ã®æ§æè¦ç´ ãç¥ã
- 36. TypeReprããType[?]ãå¾ã
- 37. TypeReprããåãåãåºã
- 38. åãçãããã©ãã調ã¹ã
- 39. é¨ååãã©ãã調ã¹ã
- 40. åã¨ã¤ãªã¢ã¹ã解決ãã
- 41. åã¬ãã«ã®è¨ç®çµæãå¾ã
- 42. åãæ±åãã
- 43. åã®æ§é ãå帰çã«èµ°æ»ãã
- 44. æ§é çãªåãå帰çã«èµ°æ»ãã
- ã·ã³ãã«
- 45. å®ç¾©ãåç §ãã
- 46. ã³ã³ãããªã³ãªãã¸ã§ã¯ããåç §ãã
- 47. ç¹å®ã®ååã®ã¡ã½ãããå¼ã¶å¼ãçæãã
- 48. ãªã¼ãã¼ãã¼ããããã¡ã½ãããå¼ã¶å¼ãçæãã
- 49. å¼æ°ã®ãªãã¡ã½ãããå¼ã¶å¼ãçæãã
- 50. æ½è±¡æ§ææ¨ã®è¦ªã辿ã
- 51. ãªãã¬ã¯ã·ã§ã³APIã®ä½¿ãæ¹ã調ã¹ã
- ã¨ã©ã¼å¦ç
- å¿ç¨
- 56. DynamicãSelectableã®selectDynamicããã¯ãåãã
- 57. DynamicãSelectableã®applyDynamicNamedããã¯ãåãã
- 58. å¯å¤é·å¼æ°ãå¼ã®ãªã¹ãã«ãã
- 59. å¯å¤é·å¼æ°ã®åå¼æ°ã®åãå¾ã
- 60. å¼ã®åãå¯å¤é·å¼æ°ã¨ãã¦ã¹ãã©ã¤ã¹ãã
- 61. æååè£éããã¯ãåãã
- 62. unapplyãtransparent inlineã«ãã
- 63. åå¤æ°ãã©ãã調ã¹ã
- 64. ãã¯ãã«å ·ä½çãªåå¼æ°ã渡ãããã«ãã
- 65. åã«å¯¾ããè¤éãªæ¡ä»¶ã調ã¹ã
- givenã¨ãã¯ã
- 66. ãã¯ãå ã§summonãã
- 67. ãã¯ãå ã§summonã§ããªãã£ããã³ã³ãã¤ã«ã¨ã©ã¼ã«ãã
- 68. givenããã¯ãåãã
- 69. givenãã¯ãã§åæ å ±ã ãè¨ç®ãã
- 70. givenãã¯ãã§è¨ç®ãããçµæã®åãåãåºã
- 71. åå¢çã¤ãã®åã«ãã¿ã¼ã³ããããã
- 72. åæ å ±ã®è¨ç®ããããªãgivenãã¯ãã®çæã³ã¹ããæ¸ãã
- 73. ãã¯ãããªãã¹ãgivenãã¯ãã«æ¼ãè¾¼ãã
- 74. givenãã¯ãã§åãã§ãã¯ãã¦ã¡ã½ããã®å®è£ ã§ã¯åå®å ¨ãªããæ¹ã諦ãã
- 75. givenãã¯ãã®ã¨ã©ã¼ãããããããã³ã³ãã¤ã«ã¨ã©ã¼ã«ãã
- ãã¯ãã¢ããã¼ã·ã§ã³ (å®é¨çæ©è½)
- ã³ã¼ãæ´ç
- ãã©ãã«ã·ã¥ã¼ãã£ã³ã°
- åèè³æ
- 88. ãã¯ãã«ã¤ãã¦ã®å ¬å¼ã¬ã¤ã
- 89. ã¯ã©ã¼ãã«ã¤ãã¦ã®å ¬å¼ã¬ã¤ã
- 90. ãªãã¬ã¯ã·ã§ã³ã«ã¤ãã¦ã®å ¬å¼ã¬ã¤ã
- 91. ãã¯ãã«ã¤ãã¦ã®FAQ
- 92. ãã¯ãã®ãã¹ããã©ã¯ãã£ã¹
- 93. ãã¯ãã«ã¤ãã¦ã®å ¬å¼ãªãã¡ã¬ã³ã¹
- 94. ãã¯ãã®ä»æ§
- 95. givenãã¯ãã«ã¤ãã¦ã®å ¬å¼ãªãã¡ã¬ã³ã¹
- 96. å ¬å¼ã®ãã¯ãã®ä¾
- 97. StackOverflowã§ä¾ãæ¢ã
- 98. record4sã®ãã¯ãã®ä¾
- 99. shapeless-3ã®ãã¯ãã®ä¾
- 100. circeã®ãã¯ãã®ä¾
- ãããã«
ãã¯ã
1. ã¡ã½ããããã¯ãã¨ãã¦å®ç¾©ãã
ãã¯ããå®ç¾©ããã«ã¯def
ã®åã«inline
ãã¤ã, ã¡ã½ããæ¬ä½ã¯ ${ ... }
ã®ä¸ã§ãã¯ããå®è£
ããã¡ã½ãããå¼ã¶ããã«ããã! å¼æ°ããã¯ãå®è£
ã«æ¸¡ãã¨ãã¯ã¯ã©ã¼ã'
ãã¤ãããã¨ã ãè¦ãã¦ãã!
inline def someMethod[T](arg: T): T =
${ someMethodImpl('arg) }
2. ãã¯ãã®æ¬ä½ãå®è£ ãã
ãã¯ãã®æ¬ä½ã¯æ®éã®ã¡ã½ããã ! ãã ã, å
ã®ãã¯ãã®åå¼æ°ã«ã¯: Type
ãã¤ã, å¼æ°ãè¿ãå¤ã®åã¯Expr[_]
ã«å
¥ã, using Quotes
ãããã®ã«ãªã£ã¦ããå¿
è¦ãããã! Type
ãExpr
ãQuotes
ã®ããã«import scala.quoted.*
ãå¿
è¦ã !
import scala.quoted.* def someMethodImpl[T: Type](arg: Expr[T])(using Quotes): Expr[T] = ???
3. ãã¯ãå®è£ ã®è¨æ³ã®æå³ãç¥ã
${ ... }
ã'
ã®æå³ãç¥ãããã ã£ã¦? ãã®è¨äºãèªãã§ãã!
4. ãã¯ãã§çæãããã³ã¼ãã®å 容ã確èªãã
以ä¸ã®inspect
ã®ãããªãã¯ããç¨æãã¦ããã¨, ããã¤ã«æ¸¡ããå¼ããã¯ãã§ã©ãå±éããããåºåãã¦ãããã!
import scala.quoted.* inline def inspect[T](inline x: T): T = ${ inspectImpl('x) } def inspectImpl[T: Type](x: Expr[T])(using Quotes): Expr[T] = { println(x.show) x }
5. å¼æ°ã®å¼ãè©ä¾¡ããã«ä½¿ã
å¼æ°ãinline
ã«ããå ´å, ãã¯ãå®è£
ã«æ¸¡ã£ã¦ããã®ã¯è©ä¾¡åã®å¼ã«ãªã£ã¦ããã! éã«è¨ãã¨inline
ãã¤ããªãã¨è©ä¾¡ããçµæã®å¤ãæç¸ããå¤æ°ã渡ã£ã¦ããã!
import scala.quoted.* inline def repeat5[T](inline x: T): Seq[T] = ${ repeat5Impl('x) } def repeat5Impl[T: Type](x: Expr[T])(using Quotes): Expr[Seq[T]] = '{ Seq($x, $x, $x, $x, $x) }
inspect(repeat5(println("hoge"))) // (scala.Seq.apply[scala.Unit](scala.Predef.println("hoge"), scala.Predef.println("hoge"), scala.Predef.println("hoge"), scala.Predef.println("hoge"), scala.Predef.println("hoge")): scala.collection.immutable.Seq[scala.Unit]) // hoge // hoge // hoge // hoge // hoge // val res0: Seq[Unit] = List((), (), (), (), ())
6. è¿ãå¤ã®åããã¯ãã®å®è¡çµæã«ãã£ã¦æ±ºãã
inline
ã®ä»£ããã«transparent inline
ã«ããã¨ãã¯ãå®è£
ã®å®è¡çµæã«ãã£ã¦è¿ãå¤ã®åã決ãããã¨ãã§ããã!
import scala.quoted.* transparent inline def zero[T]: Any = ${ zeroImpl[T] } def zeroImpl[T: Type](using Quotes): Expr[Any] = Type.of[T] match { case '[Int] => Expr(0) case '[String] => Expr("") }
scala> zero[Int] val res0: Int = 0 scala> zero[String] val res1: String = ""
7. ãã¯ãã®è¿ãå¤ã®åãå¶éãã
transparent inline
ãªãã¯ãã«è¿ãå¤ã®åãæ¸ãã¦ããã¨, ãã¯ãå®è£
ã®å®è¡çµæã®åã¯ãã®åã®é¨ååã«å¶éãããã!
å¶éã«æ²¿ããªãåãæ¸ãã¨æãããããæ°ãã¤ãã!
import scala.quoted.* transparent inline def zero[T]: Option[Any] = ${ zeroImpl[T] } def zeroImpl[T: Type](using Quotes): Expr[Any] = Type.of[T] match { case '[Int] => Expr(0) // ^ // Found: (0 : Int) // Required: Option[Any] case '[String] => Expr("") // ^^ // Found: ("" : String) // Required: Option[Any] }
å¶éã«æ²¿ãåãæ¸ããå ´åã¯, ãã¯ãã®ã·ã°ããã£(ãã®ä¾ã®å ´åã¯Option[Any]
)ã§ã¯ãªããã¯ãå®è£
ã®å®è¡çµæã®å(ãã®ä¾ã®å ´åã¯Some[Int]
ãSome[String]
ãNone.type
)ã§è¿ãã!
import scala.quoted.* transparent inline def zero[T]: Option[Any] = ${ zeroImpl[T] } def zeroImpl[T: Type](using Quotes): Expr[Option[Any]] = Type.of[T] match { case '[Int] => '{ Some(${ Expr(0) }) } case '[String] => '{ Some(${ Expr("") }) } case _ => '{ None } }
scala> zero[Int] val res0: Some[Int] = Some(0) scala> zero[String] val res1: Some[String] = Some() scala> zero[Int => Int] val res2: None.type = None
8. ãã¯ãã®è¿ãå¤ã®åãæ¸ããªã
transparent inline
ã®å ´åã¯ãã¯ãã®ã·ã°ããã£ã¨ã¯éãåã§è¿ã£ã¦ãã¦ãããã«ãããã, ããã¦è¿ãå¤åãæ¸ããªãã®ãã¢ãªã ã¨æãã!
transparent inline def zero[T] =
${ zeroImpl[T] }
9. ãã¯ãã§è¨ç®ãããåããã¹ããã
ãã¯ãå®è£ ã®å®è¡çµæã«ãã£ã¦åãå¤ããããªã, æå³ããåã«ãªã£ããã©ãããã¹ããããããã¡? ããééã£ãåã«ãªã£ã¦ãããã³ã³ãã¤ã«ã¨ã©ã¼ã«ãããããã¡? ããããã¨ãã¯ããããã¨ããã!
import scala.compiletime.summonInline extension [T1](anything: T1) { inline def isA[T2]: Unit = { val _ = summonInline[T1 <:< T2] } inline def isExactlyA[T2]: Unit = { val _ = summonInline[T1 =:= T2] } }
zero[Int].isA[Some[Int]]
zero[Int].isExactlyA[Option[Int]]
// Cannot prove that Some[Int] =:= Option[Int].
10. ãã¯ãã§è¨ç®ãããåãScalaTestã§ãã¹ããã
ScalaTestã§matchersã使ã£ã¦ãããªããshouldãªãã¨ãããªè¨æ³ã§ãã¹ããããããã¡? こういうのãå®ç¾©ãã¦ããã°ã§ããã!
zero[Int] shouldStaticallyBe a[Some[Int]] zero[Int] shouldStaticallyBe an[Option[Int]]
å¼
11. å®æ°å¼ã®å¤ãå¾ã
ã³ã³ãã¤ã«æã«å¤ãåãã£ã¦ãããªã, ãã¯ãå
ã§value
ãå¼ã¶ã¨å¤ãåãåºããã!
import scala.quoted.* inline def square(x: Int): Option[Int] = ${ squareImpl('x) } def squareImpl(x: Expr[Int])(using Quotes): Expr[Option[Int]] = x.value match { case Some(v) => Expr(Some(v * v)) case None => Expr(None) }
inspect(square(5)) // (scala.Some.apply[scala.Int](25): scala.Option[scala.Int]) // val res0: Option[Int] = Some(25) val i = 5 square(i) // val res1: Option[Int] = None
12. å®æ°å¼ã§ãªããã°ã³ã³ãã¤ã«ã¨ã©ã¼ã«ãã
å®æ°ããåãä»ããããªãå ´åã¯valueOrAbort
ããã¨ããã!
import scala.quoted.* inline def square(x: Int): Int = ${ squareImpl('x) } def squareImpl(x: Expr[Int])(using Quotes): Expr[Int] = { val v = x.valueOrAbort Expr(v * v) }
square(5) // val res0: Int = 25 val i = 5 square(i) // ^ // Expected a known value.
13. å®æ°å¤ã®å¼ãä½ã
æ¢ã«ä¾ã«ç»å ´ãã¦ããããå¯ãã¦ãããããããªãã, ãã¯ãã®ä¸ã§Expr(å¤)
ã¨ããã¨, å®æ°å¤ã表ãã³ã¼ãã«ãªãã!
Expr(v * v)
14. ã³ã¼ããçæãã
æ¢ã«ä¾ã«ç»å ´ãã¦ããããå¯ãã¦ãããããããªãã, ãã¯ãã®ä¸ã§ã¯ã©ã¼ãã使ã£ã¦'{ ä»»æã®Scalaã®ã³ã¼ã }
ã¨ããã¨, ä»»æã®ã³ã¼ããçæã§ããã!
'{ None }
15. çæã³ã¼ãã®ä¸ã«è¨ç®ãããå¤ãåãè¾¼ã
ããã«ã¯ã©ã¼ã'{ ... }
ã®ä¸ã«ã¯ä»»æã®å¼ãã¹ãã©ã¤ã¹$
ã§åãè¾¼ããã!
'{ Some(${ Expr(0) }) }
16. å¼ããã¿ã¼ã³ããããã
Expr
åã®å¤ã¯ã¯ã©ã¼ã'{ ... }
ã§ãã¿ã¼ã³ãããã§ããã! ã¹ãã©ã¤ã¹${ ... }
ããé¨åã¯å¤æ°ã«æç¸ã§ããã! 以ä¸ã®rewriteFlatMap
ã¯List
ã®map(...).flatten
ãflatMap(...)
ã«æ¸ãæããã!
import scala.quoted.* inline def rewriteFlatMap[T](inline e: List[T]): List[T] = ${ rewriteFlatMapImpl('e) } def rewriteFlatMapImpl[T: Type]( e: Expr[List[T]], )(using Quotes): Expr[List[T]] = e match { case '{ type t type u <: IterableOnce[T] (${ ls }: List[`t`]) .map(${ f }: `t` => `u`) .flatten } => '{ ${ ls }.flatMap(${ f }) } case _ => e }
inspect(rewriteFlatMap(List(1, 2, 3).map(x => List(x, x*x)).flatten)) // (scala.List.apply[scala.Int](1, 2, 3).flatMap[scala.Int](((x: scala.Int) => scala.List.apply[scala.Int](x, x.*(x)))): scala.collection.immutable.List[scala.Int]) // val res0: List[Int] = List(1, 1, 2, 4, 3, 9)
17. å¼ãã¿ãã«ã«ãã¿ã¼ã³ããããã
ã¿ãã«ã(_, _)
ã§æ¸ãã¦ã_ -> _
ã§æ¸ãã¦ãã©ã¡ãã§ãããããã«ãããã¨ãã£ã¦ããããã¡? ããããã°ããã!
def exprTupleOf[A: Type, B: Type]( e: Expr[(A, B)], )(using Quotes): (Expr[A], Expr[B]) = e match { case '{ (${ a }: A, ${ b }: B) } => (a, b) case '{ ArrowAssoc(${ a }: A).->(${ b }: B) } => (a, b) }
18. å¼ã®ãã¿ã¼ã³ãããã§ä¸è¦ãªå¤æ°ãæç¸ããªã
æç¸ããªãã¦ããã¨ãã¯${ _ }
ã«ããã¨ããã!
def exprSnd[A: Type, B: Type]( e: Expr[(A, B)], )(using Quotes): Expr[B] = e match { case '{ (${ _ }: A, ${ b }: B) } => b case '{ ArrowAssoc(${ _ }: A).->(${ b }: B) } => b }
19. å¼ã®ã³ã³ãã¤ã«æã®åãå¾ã
æ¢ã«ä¾ã«è¿ããã®ãç»å ´ãã¦ããããå¯ãã¦ãããããããªãã, '{ e: tpe }
ã¿ããã«åå(å°æå)ã¤ãã§å¼ã«ãã¿ã¼ã³ãããããã¨, ãã®å¼ã®ã³ã³ãã¤ã«æã®åãåãåºããã!
val e: Expr[A] = ??? e match { case '{ ${ _ }: tpe } => ??? }
åã¯ã¯ã©ã¼ãã®å
ã¨å¤ã§æ¸ãæ¹ãå¤ãããªã($
ã§æ¬ã£ããããªã)ç¹ã«æ³¨æããããª! ã¡ãªã¿ã«, ãã¿ã¼ã³ä¸ã®å°æåã®åãæ°ããå¤æ°æç¸ã®å®£è¨ã§ãªãã¨ãã¯`...`
ã§æ¬ãã«ã¼ã«ã . ããã¯rewriteFlatMap
ã®ä¾ã§ãè¦ããª!
20. å¼ãå°åãã
inspect
ã®å®ç¾©ã§æ¢ã«ãã£ã¦ããã, Expr[?]
ã«å¯¾ãã¦show
ãå¼ã¶ã¨å¼ãå°åã§ããã!
def inspectImpl[T: Type](x: Expr[T])(using Quotes): Expr[T] = {
println(x.show)
x
}
å
21. åã®æ å ±ãå¾ã
åã«å¯¾ãã¦ãªã«ãããã«ã¯Type[T]
åã®å¤ãå¾ããã . Type.of
ã§å¾ãããã!
val tpe: Type[T] = Type.of[T]
22. Type
ããåãåãåºã
Type[T]
ã¯'[ ... ]
ã§ãã¿ã¼ã³ãããã§ããã! å®éã®åãä¸æãªType[?]
ãããåãåãåºããã¨ãã§ããã!
val tpe: Type[?] = ??? tpe match { case '[ t ] => ??? }
23. åããã¿ã¼ã³ããããã
åã®æ§é ã«ããã¿ã¼ã³ãããã§ããã! ã¿ãã«åãã©ãã調ã¹ãã¨ãã¯*:
ã§ãã¿ã¼ã³ãããããã¨ããã!
def isTuple[T: Type](using Quotes): Expr[Boolean] = { import quotes.reflect.* val b = Type.of[T] match { case '[_ *: _] => true case _ => false } Expr(b) }
24. åãå°åãã
Type.show
ã§åãå°åã§ããã!
println(Type.show[String]) // scala.Predef.String
å¼ã®æ½è±¡æ§ææ¨
25. å¼ã®æ½è±¡æ§ææ¨ãå¾ã
Expr[?]
ã«å¯¾ãã¦asTerm
ããã¨, å¼ã®æ½è±¡æ§ææ¨(Term
åã®å¤)ãå¾ãããã!
'{ 1 + 1 }.asTerm
26. ãªãã©ã«ã®æ½è±¡æ§ææ¨ãä½ã
Term
ã®é¨ååã¨ãã¦æ½è±¡æ§ææ¨ã®æ§æè¦ç´ ãå®ç¾©ããã¦ãã¦, Literal
ããªãã©ã«å¤ã表ãã¦ããã!
import quotes.reflect.* val term: Term = Literal(StringConstant("foo"))
27. å¼ã®æ§é ãå°åãã
Term
åãtoString
ããã¨ãã®ã¾ã¾æ§é ãåºåãããã!
println('{ 1 + 1 }.asTerm) // Inlined(Ident(MacroTips$),List(),Apply(Select(Literal(Constant(1)),+),List(Literal(Constant(1)))))
29. æ½è±¡æ§ææ¨ããå¼ãä½ã
Term
ã®asExprOf
ãå¼ã¶ã¨, æå®ããåã®Expr[?]
ã«å¤æã§ããã!
import quotes.reflect.* val term: Term = Literal(StringConstant("foo")) val expr: Expr[String] = term.asExprOf[String]
asExprOf
ã«ãªãã®åã渡ãã¦ããã¯ãã®ã³ã³ãã¤ã«æã«ã¯æããã, ééã£ãåã渡ãã¨ãã¯ãã®å®è¡æ(æ®éã®ã³ã³ãã¤ã«æ)ã«ã¨ã©ã¼ã«ãªãããæ°ãã¤ããããª!
import quotes.reflect.* val term: Term = Literal(StringConstant("foo")) val expr: Expr[String] = term.asExprOf[Int] // Exception occurred while executing macro expansion. // java.lang.Exception: Expr cast exception: "foo" // of type: "foo" // did not conform to type: scala.Int
åã®æ½è±¡æ§ææ¨
31. åãçãå°åãã
TypeRepr
ã®show
ã使ãã¨ããã±ã¼ã¸åãçç¥ãã¦åãå°åã§ããã!
import quotes.reflect.* println(TypeRepr.of[String].show(using Printer.TypeReprShortCode)) // String
32. Type
ããæ½è±¡æ§ææ¨ãå¾ã
Type[?]
ããTypeRepr
ãå¾ãã«ã¯, ãã£ãããã¿ã¼ã³ãããã§åãåãåºãã¦ããTypeRepr.of
ããã¨ããã!
val tpe: Type[?] = ??? tpe match { case '[tpe] => TypeRepr.of[tpe] }
33. ãªãã©ã«åã®æ½è±¡æ§ææ¨ãä½ã
TypeRepr
ã®é¨ååã¨ãã¦åã®æ½è±¡æ§ææ¨ã®æ§æè¦ç´ ãå®ç¾©ããã¦ãã¦, ConstantType
ããªãã©ã«åã表ãã¦ããã!
import quotes.reflect.* ConstantType(StringConstant("foo"))
34. åã®æ§é ãå°åãã
TypeRepr
ã®show
ã使ãã¨åã®æ§é ãå°åã§ããã!
import quotes.reflect.* println(TypeRepr.of[String].show(using Printer.TypeReprStructure)) // TypeRef(TermRef(ThisType(TypeRef(NoPrefix(), "scala")), "Predef"), "String") println(TypeRepr.of[(Int, String)].show(using Printer.TypeReprStructure)) // AppliedType(TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Tuple2"), List(TypeRef(TermRef(ThisType(TypeRef(NoPrefix(), "<root>")), "scala"), "Int"), TypeRef(TermRef(ThisType(TypeRef(NoPrefix(), "scala")), "Predef"), "String"))) println(TypeRepr.of[{ val name: String; val age: Int }].show(using Printer.TypeReprStructure)) // Refinement(Refinement(TypeRef(ThisType(TypeRef(NoPrefix(), "lang")), "Object"), "name", TypeRef(TermRef(ThisType(TypeRef(NoPrefix(), "scala")), "Predef"), "String")), "age", TypeRef(TermRef(ThisType(TypeRef(NoPrefix(), "<root>")), "scala"), "Int"))
å®ã¯TypeRepr
ãtoString
ãã¦ãã ãããåãã ! ãã£ã¡ã ãè¦ãã¦ããã°ãããª!
println(TypeRepr.of[String]) // TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class scala)),object Predef),type String)
36. TypeRepr
ããType[?]
ãå¾ã
TypeRepr
ã®asType
ãå¼ã¶ã¨Type[?]
ã«å¤æã§ããã!
import quotes.reflect.* ConstantType(StringConstant("foo")).asType
37. TypeRepr
ããåãåãåºã
asType
ãããã®ã«ãã¿ã¼ã³ãããããã°åãåãåºããã!
import quotes.reflect.* ConstantType(StringConstant("foo")).asType match { case '[tpe] => ??? }
38. åãçãããã©ãã調ã¹ã
TypeRepr
ã®=:=
ã使ãã¨2ã¤ã®åãçãããã©ãã調ã¹ãããã!
import quotes.reflect.* TypeRepr.of[String] =:= TypeRepr.of[scala.Predef.String] // true
39. é¨ååãã©ãã調ã¹ã
TypeRepr
ã®<:<
ã使ãã¨é¨ååãã©ãã調ã¹ãããã!
import quotes.reflect.* TypeRepr.of[(Int, String)] <:< TypeRepr.of[Tuple] // true
40. åã¨ã¤ãªã¢ã¹ã解決ãã
åã¨ã¤ãªã¢ã¹ã解決ãããã¨ããããããã¡? ãããªã¨ãã¯TypeRepr
ã®dealias
ãå¼ã¶ã¨ããã!
type MyInt = Int
import quotes.reflect.* val tpr = TypeRepr.of[MyInt].dealias println(tpr.show(using Printer.TypeReprShortCode)) // Int
41. åã¬ãã«ã®è¨ç®çµæãå¾ã
åã¬ãã«ã®match
ã¨ãã§è¨ç®ããããã¨ã£ã¦ããããã¡? ãã®è¨ç®çµæãç¥ãããããã¡? ãããªã¨ãã¯TypeRepr
ã®simplified
ãå¼ã¶ã¨è¨ç®ãã¦ãããã!
def isTuple1[T: Type](using Quotes): Expr[String] = { import quotes.reflect.* val tpr = TypeRepr.of[ T match { case _ *: _ => true case _ => false }, ] Expr(tpr.show) }
inline isTuple[T]: String = ${ isTuple1[T] } isTuple[(Int, Int)] // val res0: String = scala.Tuple2[scala.Int, scala.Int] match { // [_$1 >: scala.Nothing <: scala.Any, _$2 >: scala.Nothing <: scala.Tuple] => case scala.*:[_$1, _$2] => true // case scala.Any => false // }
def isTuple2[T: Type](using Quotes): Expr[String] = { import quotes.reflect.* val tpr = TypeRepr.of[ T match { case _ *: _ => true case _ => false }, ] Expr(tpr.simplified.show) }
inline isTuple[T]: String = ${ isTuple2[T] } isTuple[(Int, Int)] // val res0: String = true
42. åãæ±åãã
Scalaã§ã¯ãªã«ãã¨ã·ã³ã°ã«ãã³åã«ãªã£ã¦ããããã¡? TypeRepr
ã®widen
ã§ã·ã³ã°ã«ãã³ã§ã¯ãªãåã«ã§ããã!
val tpr = TypeRepr.of[3] tpr.show(using Printer.TypeReprShortCode) // 3
val tpr = TypeRepr.of[3].widen tpr.show(using Printer.TypeReprShortCode) // Int
43. åã®æ§é ãå帰çã«èµ°æ»ãã
åã®æ§é ã辿ãã«ã¯å帰ãããã¨ã«ãªãã! @tailrec
ããã¾ã使ã£ã¦ããããª!
import scala.quoted.* import scala.annotation.tailrec def seqFromTuple[T: Type](using Quotes): Seq[Type[?]] = { @tailrec def rec[T: Type](acc: Seq[Type[?]] = Seq.empty): Seq[Type[?]] = Type.of[T] match { case '[ head *: tail ] => rec[tail](acc :+ Type.of[head]) case _ => acc } rec[T]() }
44. æ§é çãªåãå帰çã«èµ°æ»ãã
Scala 3ã®structural typesã¯Refinement
ã¨ããTypeRepr
ã§, å³ã®ãã£ã¼ã«ãã»ã©æ§ææ¨ã®æ ¹ã«è¿ãæ¹ã«é
ç½®ããã¦ãã¦, å帰ã§è¾¿ãã¨å³ããè¦ããã¨ã«ãªããã注æãå¿
è¦ã .
import scala.quoted.* import scala.annotation.tailrec def seqOfRefinement[T: Type](using Quotes): Seq[Type[?]] = { import quotes.reflect.* @tailrec def rec(tpr: TypeRepr, acc: Seq[Type[?]]): Seq[Type[?]] = tpr match { case Refinement(base, fieldName, fieldType) => val nameType = ConstantType(StringConstant(fieldName)).asType (nameType, fieldType.asType) match { case ('[name], '[tpe]) => rec(base, Type.of[(name, tpe)] +: acc) } case _ => acc } rec(TypeRepr.of[T], Seq.empty) }
for { tpe <- seqOfRefinement[{ val name: String; val age: Int }] } println(tpe match { case '[t] => Type.show[t] }) // scala.Tuple2["name", java.lang.String] // scala.Tuple2["age", scala.Int]
ã·ã³ãã«
45. å®ç¾©ãåç §ãã
TypeRepr
ã®typeSymbol
ã§åã®Symbol
ãåå¾ããã¨, å®ç¾©ãªã©ãåç
§ã§ããã!
class A { def foo: Int = ??? def bar: String = ??? }
import quotes.reflect.* println(TypeRepr.of[A].typeSymbol.declarations.map(_.name)) // List(<init>, foo, bar)
46. ã³ã³ãããªã³ãªãã¸ã§ã¯ããåç §ãã
åã®Symbol
ããã¯companionModule
ã§ã³ã³ãããªã³ãªãã¸ã§ã¯ãã, companionClass
ã§ãã®åã®Symbol
ãå¾ãããã!
import quotes.reflect.* val sym = TypeRepr.of[A].typeSymbol val companion = sym.companionModule val companionClass = sym.companionClass
47. ç¹å®ã®ååã®ã¡ã½ãããå¼ã¶å¼ãçæãã
Select.unique
ã§ã¡ã½ãããé¸æãããã¨ã§, ã¡ã½ããå¼åºãã®å¼ãçæã§ããã!
class A { def foo: Int = ??? def bar: String = ??? } object A { def apply(): A = new A }
inline def genericApply[T]: T = ${ genericApplyImpl[T] } def genericApplyImpl[T: Type](using Quotes): Expr[T] = { import quotes.reflect.* val sym = TypeRepr.of[T].typeSymbol Select .unique(Ref(sym.companionModule), "apply") .appliedToArgs(List()) .asExprOf[T] }
genericApply[A]
// val res0: A = A@6681707
48. ãªã¼ãã¼ãã¼ããããã¡ã½ãããå¼ã¶å¼ãçæãã
Select.overloaded
ã使ã!
49. å¼æ°ã®ãªãã¡ã½ãããå¼ã¶å¼ãçæãã
appliedToNone
ã使ã! ãå¼æ°ã®ãªãã¡ã½ãããã¨ããã®ã¯toString
ã¿ããã«()
ãã¤ããã«å¼ã¶ã¡ã½ããã®ãã¨ã .
50. æ½è±¡æ§ææ¨ã®è¦ªã辿ã
Symbol
ã®spliceOwner
ãowner
ã§æ½è±¡æ§ææ¨ã®è¦ªè¦ç´ ã辿ããã! 以ä¸ã§ã¯val foo =
ã®é¨å(ValDef
)ã¾ã§è¦ªã辿ããã¨ã§, val
ã§å®£è¨ããååããã¯ãå
ã§ä½¿ã£ã¦ããã!
case class Named(name: String) inline def named: Named = ${ namedImpl } def namedImpl(using Quotes): Expr[Named] = { import quotes.reflect.* def enclosingTerm(sym: Symbol): Symbol = sym match { case _ if sym.flags is Flags.Macro => enclosingTerm(sym.owner) case _ if !sym.isTerm => enclosingTerm(sym.owner) case _ => sym } val name = enclosingTerm(Symbol.spliceOwner).name '{ Named(${ Expr(name) }) } }
val foo = named // val foo: Named = Named(foo)
åè: Scala 3 マクロ入門 · eed3si9n
51. ãªãã¬ã¯ã·ã§ã³APIã®ä½¿ãæ¹ã調ã¹ã
Term
, TypeRepr
, Symbol
ãªã©, import quotes.reflect.*
ãã¦ä½¿ããã®ã®ãã¨ããªãã¬ã¯ã·ã§ã³APIã¨è¨ãã!
ãªãã¬ã¯ã·ã§ã³APIã§å¯è½ãªæä½ãç¥ãã«ã¯, APIãªãã¡ã¬ã³ã¹ãè¦ããããscala.quoted.Quotes
ã®ã½ã¼ã¹ã³ã¼ããè¦ã¦ãã! Term
ãªãTermModule
ãå®éã®å®ç¾©ã§, TermMethods
ã«æ¡å¼µã¡ã½ãããå®ç¾©ããã¦ããã! ç¥ããããã®ã®*Module
ã¨*Methods
ãè¦ãã°ããã£ã¦ãã¨ã !
ã¨ã©ã¼å¦ç
52. ã³ã³ãã¤ã«ã¨ã©ã¼ã«ãã
ãã¯ãå®è¡ä¸ã®ã¨ã©ã¼ã¯ã³ã³ãã¤ã«ã¨ã©ã¼ã«ãªã£ã¦ã»ããããã¡? report.errorAndAbort
ã§ã³ã³ãã¤ã«ã¨ã©ã¼ã«ã§ããã! report
ã使ãã«ã¯import quotes.reflect.*
ãå¿
è¦ã !
import scala.quoted.* transparent inline def sum[T1, T2](x: T1, y: T2) = ${ sumImpl('x, 'y) } def sumImpl[T1: Type, T2: Type](x: Expr[T1], y: Expr[T2])(using Quotes, ): Expr[Any] = { import quotes.reflect.* (x, y) match { case ('{ ${ x }: Int }, '{ ${ y }: Int }) => '{ ${ x } + ${ y } } case ('{ ${ x }: String }, _) => '{ Seq(${ x }, ${ y }.toString).mkString } case _ => report.errorAndAbort("unsupported") } }
sum(1, "foo") // unsupported
53. ã³ã³ãã¤ã«ã¨ã©ã¼ã®çºçç®æã表示ãã
Scalaã®ã³ã³ãã¤ã©ã¿ããã«, ã¨ã©ã¼ã®åå ç®æããæ´è½ã«è¡¨ç¤ºãããããã¡? errorAndAbort
ã®ç¬¬2å¼æ°ã«Expr
ã渡ãã°ãããæã示ãã¦ãããã!
import scala.quoted.* transparent inline def sum[T1, T2](x: T1, y: T2) = ${ sumImpl('x, 'y) } def sumImpl[T1: Type, T2: Type](x: Expr[T1], y: Expr[T2])(using Quotes, ): Expr[Any] = { import quotes.reflect.* x match { case '{ ${ x }: Int } => y match { case '{ ${ y }: Int } => '{ ${ x } + ${ y } } case _ => report.errorAndAbort( s"""Found: ${Type.show[T2]} |Required: Int |""".stripMargin, y, ) } case '{ ${ x }: String } => '{ Seq(${ x }, ${ y }.toString).mkString } case _ => report.errorAndAbort("unsupported") } }
sum(1, "foo") // ^^^^^ // Found: java.lang.String // Required: Int
54. ã³ã³ãã¤ã«ã¨ã©ã¼ããã¹ããã
ãã¯ãã®ã¨ã©ã¼ã®åºåãæ£ããã§ãã¦ããããã¹ããããããã¡? scala.compiletime.testing.typeCheckErrors
ã使ãã¨ã§ããã!
import scala.compiletime.testing.{Error, ErrorKind} def checkErrors(errs: List[Error]): Boolean = errs.nonEmpty && errs.head.kind == ErrorKind.Typer && errs.head.message.startsWith("Found:")
import scala.compiletime.testing.typeCheckErrors checkErrors(typeCheckErrors("""sum(1, "foo")""")) // val res0: Boolean = true
55. ãã¯ãå ã®ã¨ã©ã¼ããå復ãã
report.errorAndAbort
ã¯ã³ã³ãã¤ã©ãç´æ¥ãã³ãã«ããããã, æ®éã«try
-catch
ãããã¨ãã¦ããã¾ããããªãã! ä½è¨ãªä¾å¤ã飲ã¿è¾¼ãã§ãã¾ããªãããã«ã, å復ãå¿
è¦ãªã¨ã©ã¼ã¯èªåã§ä¾å¤ãå®ç¾©ãã¦try
-catch
ããã, Option
ãEither
ãªã©ã§ããã!
å¿ç¨
56. Dynamic
ãSelectable
ã®selectDynamic
ããã¯ãåãã
Dynamic
ãSelectable
ã¯, obj.foo
ã®ãããªãã£ã¼ã«ãã¢ã¯ã»ã¹ãobj.selectDynamic("foo")
ã«æ¸ãæãã¦ããã. å®ã¯, ãã®selectDynamic
ããã¯ãã«ãã¦ããã¨, ä»»æã®ã³ã¼ãã«æ¸ãæãããã¨ãã§ããã!
import scala.language.dynamics class A extends Dynamic { inline def selectDynamic(name: String): Int = ${ A.selectImpl('name) } } object A { import scala.quoted.* def selectImpl(name: Expr[String])(using Quotes): Expr[Int] = { import quotes.reflect.* val constName = name.valueOrAbort constName match { case "zero" => Expr(0) case "one" => Expr(1) case _ => report.errorAndAbort("not implemented") } } }
val a = new A inspect(a.zero) // (0: scala.Int) // val res0: Int = 0
57. Dynamic
ãSelectable
ã®applyDynamicNamed
ããã¯ãåãã
åæ§ã«, applyDynamic
ãapplyDynamicNamed
ããã¯ãã«ããã¨, ä»»æã®ã¡ã½ããå¼åºãããã¯ãã§æ¸ãæãããã¨ãã§ããã! ã¨ãã«applyDynamicNamed
ã¯, obj.m(foo = 1)
ã®foo
ã®é¨åã®ååãæååã¨ãã¦å¾ãããã!
import scala.language.dynamics class A extends Dynamic { transparent inline def applyDynamicNamed(method: String)( inline args: (String, Any)*, ) = ${ A.applyImpl('this, 'method, 'args) } } object A { import scala.quoted.* def applyImpl( a: Expr[A], method: Expr[String], args: Expr[Seq[(String, Any)]], )(using Quotes): Expr[Any] = ??? }
58. å¯å¤é·å¼æ°ãå¼ã®ãªã¹ãã«ãã
Expr[Seq[?]]
åã§æ¸¡ããã¦ããå¯å¤é·å¼æ°ã¯, Varargs
ã¨ãã¿ã¼ã³ããããããã¨ã§å¼ã®ãªã¹ãã«ã§ããã!
import scala.language.dynamics class A extends Dynamic { transparent inline def applyDynamicNamed(method: String)( inline args: (String, Any)*, ) = ${ A.applyImpl('this, 'method, 'args) } } object A { import scala.quoted.* def applyImpl( a: Expr[A], method: Expr[String], args: Expr[Seq[(String, Any)]], )(using Quotes): Expr[Any] = { import quotes.reflect.* args match { case Varargs(list) => // list: Seq[Expr[(String, Any)]] ??? case _ => report.errorAndAbort("Expected explicit varargs sequence", args) } } }
59. å¯å¤é·å¼æ°ã®åå¼æ°ã®åãå¾ã
å¯å¤é·å¼æ°ã®åå¼æ°ã®åã¯ã¾ã¨ãã¦Any
ã«ãªã£ã¦æ¸¡ã£ã¦ããã, ãã¿ã¼ã³ãããããã°åå¼æ°ã®åããããã! 以ä¸ã®ä¾ã§ã¯tpe
ã«åå¼æ°ã®åãåãåºãã¦ããã!
import scala.language.dynamics class A extends Dynamic { transparent inline def applyDynamicNamed(method: String)( inline args: (String, Any)*, ) = ${ A.applyImpl('this, 'method, 'args) } } object A { import scala.quoted.* def applyImpl( a: Expr[A], method: Expr[String], args: Expr[Seq[(String, Any)]], )(using Quotes): Expr[Any] = { import quotes.reflect.* val triples = // triples: Seq[(String, Expr[Any], Type[?])] args match { case Varargs(list) => list.map { case '{ ($labelExpr: String, $valueExpr: tpe) } => (labelExpr.valueOrAbort, valueExpr, Type.of[tpe]) } case _ => report.errorAndAbort("Expected explicit varargs sequence", args) } ??? } }
60. å¼ã®åãå¯å¤é·å¼æ°ã¨ãã¦ã¹ãã©ã¤ã¹ãã
Seq[Expr[?]]
ã¯Expr.ofSeq
ã§Expr[Seq[?]]
ã«å¤æã§ããã! 以ä¸ã¯Set(1, 2, 3)
ã¨ããã³ã¼ããçæããã!
val exprs = Seq(Expr(1), Expr(2), Expr(3)) '{ Set(${ Expr.ofSeq(exprs) }: _*) }
61. æååè£éããã¯ãåãã
ã§ãã! ã¨ãã«å¤ãªã¨ããã¯ãªã, ãã ãã¯ãã«ããã ãã !
trait A object A { extension (sc: StringContext) { inline def a(inline args: Any*): A = ${ interpolationImpl('sc, 'args) } } import scala.quoted.* def interpolationImpl(sc: Expr[StringContext], args: Expr[Seq[Any]])(using Quotes, ): Expr[A] = ??? }
62. unapply
ãtransparent inline
ã«ãã
ãªãã¨ã§ããªã!! ã³ã³ãã¤ã©ã®ãã°ã !
ä¿®æ£ããã¦ãããã ãã, è¿ã ã§ããããã«ãªãã ãã.
63. åå¤æ°ãã©ãã調ã¹ã
TypeRepr
ã®typeSymbol
ããisTypeParam
ãå¼ã¶ã¨åå¤æ°ãã©ãã調ã¹ãããã!
import scala.quoted.* inline def isTypeVar[T]: Boolean = ${ isTypeVarImpl[T] } def isTypeVarImpl[T: Type](using Quotes): Expr[Boolean] = { import quotes.reflect.* val b = TypeRepr.of[T].typeSymbol.isTypeParam Expr(b) }
ãã¯ãã®ä¸ã§ãããtrue
ã«ãªãå ´å, ãã¯ãã®å¼åºãã³ã³ããã¹ãã§ã¯åå¼æ°ã«å
·ä½çãªåãåãããã¦ããªãã¨ãããã¨ã ãª!
def nonGenericCall: Unit = println(isTypeVar[String]) nonGenericCall // false
def genericCall[T]: Unit = println(isTypeVar[T]) genericCall[String] // true
64. ãã¯ãã«å ·ä½çãªåå¼æ°ã渡ãããã«ãã
ã ãã, ãã¯ãã«å
·ä½çãªåã渡ããªããã°ãªããªãå ´åã¯, ãã¯ããå¼ã³åºãã¦ããã¡ã½ããã¯å¿
ç¶çã«inline
ã«ãªãã!
inline def inlineCall[T]: Unit = println(isTypeVar[T]) inlineCall[String] // false
65. åã«å¯¾ããè¤éãªæ¡ä»¶ã調ã¹ã
åãæ¡ä»¶ãæºããã¦ããããType[?]
ãTypeRepr
ã®ã¤ã³ã¿ãã§ã¼ã¹ã§èª¿ã¹ãã®ã¯å¤§å¤ãªã¨ããããããã¡? ããããå ´åã¯(ãã¯ãã§ã¯ãªãæ®éã®)given
ã§æ¡ä»¶ã表ç¾ãã¦ããã¦, ãã¯ãã®ä¸ã§ã¯Expr.summon
ããã ãã«ãã¦ããã¨ç°¡åã !
以ä¸ã§ã¯opaque type
ã§è¡¨ç¾ãããTag[?]
ãã©ããã調ã¹ãIsTag[_]
ãå®ç¾©ãã¦ããã!
opaque type Tag[T] = Any object Tag { final class IsTag[T] private () object IsTag { private[Tag] val instance = new IsTag[Nothing] } given [T]: IsTag[Tag[T]] = IsTag.instance.asInstanceOf[IsTag[Tag[T]]] }
Expr.summon[Tag.IsTag[T]]
ã§ããã°T
ã¯Tag[?]
ã ã¨ãããã¨ã !
given
ã¨ãã¯ã
66. ãã¯ãå
ã§summon
ãã
Expr.summon
ã使ãã¨, ãã¯ããå¼ã³åºããç®æã®ã³ã³ããã¹ãã§given
ã¤ã³ã¹ã¿ã³ã¹ãæ¢ç´¢ã§ããã!
Expr.summon[Ordering[T]] match { case Some(ord) => ??? case None => ??? }
67. ãã¯ãå
ã§summon
ã§ããªãã£ããã³ã³ãã¤ã«ã¨ã©ã¼ã«ãã
Expr.summon
ãã¦getOrElse
ã§ã³ã³ãã¤ã«ã¨ã©ã¼ã«ããã¡ã½ãããç¨æãã¦ããã¨ä¾¿å©ã ã!
def evidenceOf[T: Type](using Quotes): Expr[T] = Expr.summon[T].getOrElse { errorAndAbort( s"No given instance of ${Type.show[T]}", ) }
68. given
ããã¯ãåãã
å®ã¯given
èªä½ããã¯ãã«ãããã¨ãã§ããã! given
ã¤ã³ã¹ã¿ã³ã¹ã®æ¢ç´¢ä¸ã«ãã¯ããå®è¡ãããã!
trait MyTypeClass[A] inline given myTypeClss[A]: MyTypeClass[A] = ${ derivedMyTypeClassImpl } import scala.quoted.* def derivedMyTypeClassImpl[A: Type](using Quotes): Expr[MyTypeClass[A]] = ???
69. given
ãã¯ãã§åæ
å ±ã ãè¨ç®ãã
given
ãtransparent inline
ã«ããã¨, åã®è¨ç®ã ããããã¯ããä½ããã!
class MyTyper[A] { type Out } transparent inline given myTyper[A]: MyTyper[A] = ${ derivedMyTyperImpl } import scala.quoted.* def derivedMyTyperImpl[A: Type](using Quotes): Expr[MyTyper[A]] = { val tpe = Type.of[A] match { case '[Int] => Type.of[Seq[Int]] case '[String] => Type.of[Option[String]] case _ => Type.of[Nothing] } tpe match { case '[tpe] => '{ new MyTyper[A] { type Out = tpe } } } }
val tp = summon[MyTyper[Int]] // val tp: MacroTips.MyTyper[Int]{type Out = Seq[Int]} = anon$1@3577de62 val x: tp.Out = Seq(3) // val x: tp.Out = List(3)
70. given
ãã¯ãã§è¨ç®ãããçµæã®åãåãåºã
以ä¸ã®ããã«ããã¨MyTyper
ã®type Out
ãtpe
ã¨ããååã§åãåºããã!
Expr.summon[MyTyper[A]] match { case Some('{ ${ _ }: MyTyper[A] { type Out = tpe } }) => ??? case _ => ??? }
71. åå¢çã¤ãã®åã«ãã¿ã¼ã³ããããã
MyTyper
ã®çµæã¯IterableOnce[A]
ã ã¨å®ç¾©ããã¦ãã¦, IterableOnce[?]
ãè¦æ±ããOnIterableOnce
ããã£ãã¨ããã.
class MyTyper[A] { type Out <: IterableOnce[A] } trait OnIterableOnce[It <: IterableOnce[?]]
ãã®å ´å, 次ã®ã³ã¼ãã¯åããªã!
Expr.summon[MyTyper[A]] match { case Some('{ ${ _ }: MyTyper[A] { type Out = tpe } }) => val tp = Type.of[OnIterableOnce[tpe]] // ^ // Type argument tpe does not conform to upper bound IterableOnce[?] ??? case _ => ??? }
ããã¯, type Out = tpe
ã¨ããã¨ãã«, ãã¨ãã¨ã®Out
ã®ä¸éããªããèæ
®ãã¦ãããªãããã ã!
ããããå ´åã¯æ¬¡ã®ããã«æ¸ãã¨ãã¾ãããã!
Expr.summon[MyTyper[A]] match { case Some('{ type tpe <: IterableOnce[A] ${ _ }: MyTyper[A] { type Out = `tpe` } }) => val _ = Type.of[OnIterableOnce[tpe]] ??? case _ => ??? }
å
ã«type tpe <: IterableOnce[A]
ã¨ä¸éã¤ãã§æç¸å¤æ°ã宣è¨ãã¦ããã¦, type Out =
ã®æ¹ã§ã¯`tpe`
ã¨ããã¯ã¯ã©ã¼ããããã¨ã§å®£è¨æ¸ã¿ã®åãåç
§ãã¦å¶ç´ã課ãã¦ãããã ãª!
72. åæ
å ±ã®è¨ç®ããããªãgiven
ãã¯ãã®çæã³ã¹ããæ¸ãã
ãã¯ãã®ä¸ã§new
ããã¨ãã¯æ°ãã¤ãã!
'{ new MyTyper[A] { type Out = tpe } }
ããã ã¨æ¯åæ°ããªã¤ã³ã¹ã¿ã³ã¹ãä½ããã¦ãã¾ãã! åæ å ±ãéãã ããªãã¤ã³ã¹ã¿ã³ã¹ã¯1ã¤ã§ååã !
final class MyTyper[A] private () { type Out } object MyTyper { val instance = new MyTyper[Nothing] }
def derivedMyTyperImpl[A: Type](using Quotes): Expr[MyTyper[A]] = { val tpe = ??? tpe match { case '[tpe] => '{ MyTyper .instance .asInstanceOf[ MyTyper[A] { type Out = tpe }, ] } } }
73. ãã¯ãããªãã¹ãgiven
ãã¯ãã«æ¼ãè¾¼ãã
given
ãã¯ãããã¾ã使ãã¨, ãã¹ã¦ã®ãã¯ããgiven
ã¤ã³ã¹ã¿ã³ã¹ã®è¨ç®ã®é¨åã«æ¼ãè¾¼ãã§ãã¾ãããã¨ãå¤ãã!
ã³ã³ãã¯ããªä¾ãæ®éçãªããæ¹ã示ãã®ã¯é£ããããå®éã«ãããã¦ããä¾ãè²¼ã£ã¦ããã.
inline given decoder[R <: %](using r: RecordLike[R], dec: Decoder[ArrayRecord[r.TupledFieldTypes]], c: typing.Record.Concat[%, ArrayRecord[r.TupledFieldTypes]], ev: c.Out =:= R, ): Decoder[R] = new Decoder[R] { final def apply(c: HCursor): Decoder.Result[R] = dec(c).map(ar => ev(ar.toRecord)) }com.github.tarao.record4s.circe.Codec
ã³ã¼ãã®æå³ã¯ããããªãã¦ããã! c.Out
ã¯given
ãã¯ãã§è¨ç®ãããåã§, ããããã¾ãä»ã®å¶ç´ã¨çµã¿åããããã¨ã§apply
ã¡ã½ããæ¬ä½ã¯ãã¯ããªãã§æ¸ãã¦ãã¾ã£ã¦ããç¹ã ãè¦ã¦ãã!
74. given
ãã¯ãã§åãã§ãã¯ãã¦ã¡ã½ããã®å®è£
ã§ã¯åå®å
¨ãªããæ¹ã諦ãã
given
ãã¯ãã§åãè¨ç®ããã®ã¯, ç¬èªã®åæ¤æ»ã®ä»çµã¿ãå®è£
ãã¦ããã¨èãããã¨ãã§ããã! ä¸æ£ãªä½¿ãæ¹ã¯given
ãã¯ãã®ã¤ã³ã¹ã¿ã³ã¹åã®å¤±æã¨ãã¦æ¤åºã§ãããã, æ¤æ»ã«éã£ã¦ãã¾ãã°asInstanceOf
ããã¾ãã£ã¦ãåé¡ãªãã¯ãã !
ãããã³ã³ãã¯ããªä¾ãèããã®ãé¢åã ããä½ãã®ã¯é£ãããã, å®éã«ä½¿ããã¦ããä¾ãè²¼ã£ã¦ããã!
def lookup[R <: %, L <: String & Singleton, Out](record: R, label: L)(using Lookup.Aux[R, L, Out], ): Out = record.__lookup(label).asInstanceOf[Out]com.github.tarao.record4s.Record.lookup
Lookup.Aux
ãåãè¨ç®ããgiven
ãã¯ãã . ãã®given
ã¤ã³ã¹ã¿ã³ã¹ãå¾ãããæç¹ã§, record.__lookup(label)
ã®çµæ(éçã«ã¯Any
å)ã¯Out
åã«ãªã£ã¦ãããã¨ãä¿è¨¼ããã¦ãããã, ä¸è¦ããã¨å®å
¨ã§ã¯ãªãasInstanceOf
ãå¼ãã§ãåé¡ãªãã¨ããããã !
75. given
ãã¯ãã®ã¨ã©ã¼ãããããããã³ã³ãã¤ã«ã¨ã©ã¼ã«ãã
given
ãã¯ãã®ä¸ã§ã³ã³ãã¤ã«ã¨ã©ã¼ã«ãªãã¨, ã¨ã©ã¼ã¡ãã»ã¼ã¸ã¯è¡¨ç¤ºãããã«åã«No given instance of ~
ã¨è¨ããã¦ãã¾ã. ããã¯ãããã«ãã! å©ç¨è
ã«ã¯ä½¿ãæ¹ãã©ãæªãã£ãã®ã説æãã¦ãããæ¹ãããã ãã.
ãã¾ãããããæ¹ã§ã¯ãªããããããªãã, given
ãã¯ãã®å®è¡ã¯å¿
ãæåããããã«ãã¦, ã¨ã©ã¼æã«ã¯type Out = Nothing
ã«ãããã¨ã§, ããããããã¨ã©ã¼ã¡ãã»ã¼ã¸ã表示ããæãããã!
æºåã¨ãã¦æ¬¡ã®ãããªãã®ãç¨æãã¦ãã.
trait MaybeError { type Out type Msg <: String } inline def showTypingError(using err: typing.MaybeError): Unit = { import scala.compiletime.{constValue, erasedValue, error} inline erasedValue[err.Out] match { case _: Nothing => error(constValue[err.Msg]) case _ => // no error } } inline def withPotentialTypingError[T]( inline block: => T, )(using err: typing.MaybeError): T = { showTypingError block }
åãè¨ç®ããããã®åã¯MaybeError
ãç¶æ¿ãã¦ãã.
final class MyTyper[A] private () extends MaybeError object MyTyper { val instance = new MyTyper[Nothing] }
ã¨ã©ã¼ã®ã¨ãã¯type Out = Nothing
ã«ãã¦type Msg
ã«ã¨ã©ã¼ã¡ãã»ã¼ã¸ãå
¥ãã¦ãã.
def derivedMyTyperImpl[A: Type](using Quotes): Expr[MyTyper[A]] = { val tpe = ??? if (/* ã¨ã©ã¼æ */) { '{ MyTyper .instance .asInstanceOf[ MyTyper[A] { type Out = Nothing type Msg = "ããããããã¨ã©ã¼ã¡ãã»ã¼ã¸" }, ] } } else { tpe match { case '[tpe] => '{ MyTyper .instance .asInstanceOf[ MyTyper[A] { type Out = tpe type Msg = Nothing }, ] } } } }
ãããã使ãã¡ã½ããã¯ä»¥ä¸ãæºããããã«ãã.
inline
ã«ãã- æ¬ä½ã
withPotentialTypingError { ... }
ã§å²ã
inline def withMyTyper[A](using t: MyTyper[A]): t.Out =
withPotentialTypingError {
???
}
ãããããã¨ã§given
ãã¯ãã®ã¨ã©ã¼ã¡ãã»ã¼ã¸ã, using
ãã¦ããã¡ã½ããã¾ã§ä¼æããããã¨ãã§ããã!
ãã¯ãã¢ããã¼ã·ã§ã³ (å®é¨çæ©è½)
76. ãã¯ãã§ã¡ã½ããå®ç¾©ãæ¸ãæãã
MacroAnnotation
ã使ãã¨, ã¡ã½ããå®ç¾©ãæ¸ãæããã¢ããã¼ã·ã§ã³ãå®ç¾©ã§ããã! ãã®æ©è½ã¯å®é¨çã ãã@experimental
ã¢ããã¼ã·ã§ã³ãã¤ããããª!
以ä¸ã®ä¾ã¯ä»»æã®1å¼æ°é¢æ°ãã¡ã¢åãã@memoize
ã¢ããã¼ã·ã§ã³ã !
import scala.annotation.{experimental, MacroAnnotation} import scala.quoted.* @experimental class memoize extends MacroAnnotation { def transform(using Quotes, )(tree: quotes.reflect.Definition): List[quotes.reflect.Definition] = { import quotes.reflect.* tree match { case DefDef( name, TermParamClause(param :: Nil) :: Nil, tpt, Some(rhsTree), ) => (Ref(param.symbol).asExpr, rhsTree.asExpr) match { case ('{ $paramRefExpr: t }, '{ $rhsExpr: u }) => val cacheTpe = TypeRepr.of[collection.mutable.Map[t, u]] val cacheSymbol = Symbol.newVal( tree.symbol.owner, name + "Cache", cacheTpe, Flags.Private, Symbol.noSymbol, ) val cacheRhs = '{ collection.mutable.Map.empty[t, u] }.asTerm val cacheVal = ValDef(cacheSymbol, Some(cacheRhs)) val cacheRefExpr = Ref(cacheSymbol).asExprOf[collection.mutable.Map[t, u]] val newRhs = '{ $cacheRefExpr.getOrElseUpdate($paramRefExpr, $rhsExpr) }.asTerm val newTree = DefDef.copy(tree)( name, TermParamClause(param :: Nil) :: Nil, tpt, Some(newRhs), ) List(cacheVal, newTree) } case _ => report.error( "Annotation only supported on `def` with a single argument", ) List(tree) } } }import scala.annotation.experimental @experimental @memoize def fib(n: Int): Int = if (n <= 1) n else fib(n - 1) + fib(n - 2)Macro annotation (part 1) by nicolasstucki · Pull Request #16392 · lampepfl/dotty
import scala.annotation.experimental @experimental val r = fib(8) // val r: Int = 21
77. ãã¯ãã§ã¯ã©ã¹å®ç¾©ãæ¸ãæãã
MacroAnnotation
ã¯class
ãobject
ã«ã使ããã!
é·ãã®ã§ã³ã¼ãã¯è²¼ããªãã, ãã¨ãã°equals
ãèªåçæããã¢ããã¼ã·ã§ã³ãªãããå®ç¾©ã§ããã! ãããã使ãæ¹ã®ã¤ã¡ã¼ã¸ã ãª.
@equals class Foo(val a: String, val b: Int) //> override def equals(that: Any): Boolean = //> that match //> case that: Foo => this.a.==(that.a).&&(this.b.==(that.b)) //> case _ => false //> private lazy val hash$macro$1: Int = //> var acc = -1566937476 // scala.runtime.Statics.mix(-889275714, "Foo".hashCode) //> acc = scala.runtime.Statics.mix(acc, scala.runtime.Statics.anyHash(a)) //> acc = scala.runtime.Statics.mix(acc, b) //> scala.runtime.Statics.finalizeHash(acc, 2) //> override def hashCode(): Int = hash$macro$1lampepfl/dotty:tests/run-macros/annot-mod-class-equals/Test_2.scala
78. å¤æ°ãå®ç¾©ããã³ã¼ããçæãã
ãã¯ãã¢ããã¼ã·ã§ã³ã®ã³ã¼ãä¾ãè¦ãã¨åããã, ValDef
ã§å¤æ°å®ç¾©ãä½ããã¨ãã§ããã!
val cacheTpe = TypeRepr.of[collection.mutable.Map[t, u]] val cacheSymbol = Symbol.newVal( tree.symbol.owner, name + "Cache", cacheTpe, Flags.Private, Symbol.noSymbol, ) val cacheRhs = '{ collection.mutable.Map.empty[t, u] }.asTerm val cacheVal = ValDef(cacheSymbol, Some(cacheRhs))
ãªãã¬ã¯ã·ã§ã³APIã°ããã«ãªã£ã¦ãã¾ã! Symbol
ãä½ã£ããããã®ãé¢åã ãª!
79. ã¡ã½ãããå®ç¾©ããã³ã¼ããçæãã
ã¡ã½ããå®ç¾©ã¯DefDef
ã§ä½ããã¨ãã§ããã!
val newRhs = '{ $cacheRefExpr.getOrElseUpdate($paramRefExpr, $rhsExpr) }.asTerm val newTree = DefDef.copy(tree)( name, TermParamClause(param :: Nil) :: Nil, tpt, Some(newRhs), )
æ¢åã¡ã½ãããç½®ãæããå ´åã¯Symbol
ãæ°ããä½ãå¿
è¦ã¯ãªãã¦å°ã楽ã ãª!
80. ã¯ã©ã¹ãå®ç¾©ããã³ã¼ããçæãã
ã¯ã©ã¹å®ç¾©ã¯ClassDef
ã§ä½ããã¨ãã§ããã! ããæ¹ã¯@equals
ã®ä¾ã新規にクラスを追加する例ãè¦ã¦ãã!
ã³ã¼ãæ´ç
81. çæã³ã¼ãã¯ãªãã¹ãã³ã³ãã¯ãã«ãã
ãã¯ãã§çæããã³ã¼ãã¯ãªãã¹ãã³ã³ãã¯ãã«ããããª! ã§ãªãã¨å®è¡ãã¡ã¤ã«ã巨大ã«ãªã£ã¦ãã¾ãã!
82. å¤ããèªç±ã«ã¯ã¢ã¯ã»ã¹ã§ããªãã¡ã½ããããã¯ãã®çæã³ã¼ãã§ä½¿ã
ãã¯ãã«ããçæã³ã¼ãã巨大ã«ãªã£ã¦ããã, ãã¯ãã§ã¯ãªãã¡ã½ããã«æ¬ãåºãã¦, ãã®ã¡ã½ããããã¯ãå
ããå¼ã³åºãããã«ããã¨ããã! ãã ã, ãã¯ãããå¼ã°ããã¡ã½ããã¯private
ã«ã¯ã§ããªããã注æããããª. ããã±ã¼ã¸private
ãªã大ä¸å¤«ã ã.
83. using Quotes
ããã¡ãã¡æ¸ããªãã¦ãããã
using Quotes
ããã¡ãã¡æ¸ãã®ã¯é¢åã ããã¡?
ãããã¬ãã«ã®ãã¯ãå®è£
ã¯ä»æ¹ããªãã, ãã¯ãå®è£
ã§ä½¿ããµãã«ã¼ãã³ã¯ä»¥ä¸ã®ãããªInternalMacros
ã«ã¾ã¨ãã¦ããã¨, using Quotes
ãæ¸ããªãã¦ãããªã£ã¦ããããããããããªãã!
class InternalMacros(using scala.quoted.Quotes) { import scala.quoted.* import quotes.reflect.* def subroutine(...) ... // using Quotes ä¸è¦ } object InternalMacros { import scala.quoted.* given (using Quotes): InternalMacros = new InternalMacros transparent inline def internal(using i: InternalMacros): i.type = i inline def withInternal[T](using Quotes, InternalMacros)( inline block: InternalMacros ?=> T, ): T = block(using summon[InternalMacros]) }
ãããã¬ãã«ã®ãã¯ãå®è£ ã§ã¯ããããæ³å®ã !
import InternalMacros.{internal, withInternal} def macroImpl(...)(using Quotes): Expr[Any] = withInternal { import internal.* subroutine(...) }
ãã©ãã«ã·ã¥ã¼ãã£ã³ã°
84. Nothing
ãã¿ãã«ã«ããããã¦ãã¾ãåé¡ã®å¯¾ç
ãªãã ãNothing
(ãããã¯åå¤æ°??)ãã¿ãã«ã«ããããã¦ãã¾ããã¨ããã!
ããééãããé å¼µã£ã¦é¿ãããããªãã ãã.
if TypeRepr.of[T] != TypeRepr.of[Nothing]
ããããæ¹ãããã°ãããæãã¦ã»ãã!
85. ãã¯ãã®ä¸ã§åå¼æ°ã®æ å ±ã失ãããå ´åã®å¯¾ç
ãªããgiven
ãã¯ãã®åå¼æ°ã®æ
å ±ãä¸é¨å¤±ããã¦ãã¾ããã¨ããã!
å ¨ãæå³ã®ãªãcontext boundã1ã¤æãã¨å¤§ä¸å¤«ã ã£ããããããã .
trait Context[T]
transparent inline given [T: Context]: MyTyper[T] = ???
åå ãæ£ããåé¿çãç¥ã£ã¦ãã人ãããããããæãã¦ã»ãã!
86. ãã¯ãå ã®å¤æ°ã§unusedè¦åãåºã¦ãã¾ãå ´åã®å¯¾ç
ãã¿ã¼ã³ã®ä¸ã§type
ãæ¸ãã¦ããã¨ããªã©, æªä½¿ç¨ã®ãã¼ã«ã«å¤æ°ã¨èª¤å¤å®ããããã¨ããã! @nowarn("msg=unused local")
ãã¦ãã¾ãã!
87. ã³ã³ãã¤ã©ã®ã¯ã©ãã·ã¥ããããã°ãã
ã³ã³ãã¤ã©ãã¯ã©ãã·ã¥ãã¦å°ã£ãã-Xcheck-macros
ãã¤ãã¦ã¿ãã¨ããã!
詳ããã¯ãããè¦ã¦ãã!
åèè³æ
88. ãã¯ãã«ã¤ãã¦ã®å ¬å¼ã¬ã¤ã
89. ã¯ã©ã¼ãã«ã¤ãã¦ã®å ¬å¼ã¬ã¤ã
90. ãªãã¬ã¯ã·ã§ã³ã«ã¤ãã¦ã®å ¬å¼ã¬ã¤ã
91. ãã¯ãã«ã¤ãã¦ã®FAQ
92. ãã¯ãã®ãã¹ããã©ã¯ãã£ã¹
93. ãã¯ãã«ã¤ãã¦ã®å ¬å¼ãªãã¡ã¬ã³ã¹
94. ãã¯ãã®ä»æ§
95. given
ãã¯ãã«ã¤ãã¦ã®å
¬å¼ãªãã¡ã¬ã³ã¹
96. å ¬å¼ã®ãã¯ãã®ä¾
97. StackOverflowã§ä¾ãæ¢ã
98. record4sã®ãã¯ãã®ä¾
99. shapeless-3ã®ãã¯ãã®ä¾
100. circeã®ãã¯ãã®ä¾
ãããã«
ã100é£çºãã£ã¦è¨ã£ã¦æ¬å½ã«100åããã¨ãé ããããããããã¼ã®!