我正在尝试通过 Scala 3.0.0-M2 中的宏获取函数名称我提出的解决方案使用 TreeAccumulator
import scala.quoted._
inline def getName[T](inline f: T => Any): String = ${getNameImpl('f)}
def getNameImpl[T](f: Expr[T => Any])(using Quotes): Expr[String] = {
import quotes.reflect._
val acc = new TreeAccumulator[String] {
def foldTree(names: String, tree: Tree)(owner: Symbol): String = tree match {
case Select(_, name) => name
case _ => foldOverTree(names, tree)(owner)
}
}
val fieldName = acc.foldTree(null, Term.of(f))(Symbol.spliceOwner)
Expr(fieldName)
}
Run Code Online (Sandbox Code Playgroud)
调用此代码时会生成函数的名称:
case class B(field1: String)
println(getName[B](_.field1)) // "field1"
Run Code Online (Sandbox Code Playgroud)
我想知道这是否可以使用引号以更简单的方式完成。
我想实现proxy一些特征A(例如委托方法调用到一些 rpc 调用),像这样
def clientProxy[A](using Type[A], Quotes): Expr[A] = {
import quotes.reflect._
val defTrees: List[Tree] = TypeRepr.of[A].typeSymbol.memberFields.collect {
case mf if mf.isDefDef =>
???
}
val exprs = Expr.ofList(defTrees.map(_.asExpr))
'{
new A {
$exprs
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是编译器抱怨
A is not a class type
Run Code Online (Sandbox Code Playgroud) 我已经看到这个?=>符号出现在 Scala 代码和一些关于 Scala 3 的讨论帖子中,所以我假设它是一个 Scala 3+ 符号。通过文档或 Google 搜索时什么也没有出现,但它看起来像是Function类型的语法糖,所以它可能与类型和函数有关。这是什么意思?
让我们从以下内容开始
val x = List(1, 2, "a")
Run Code Online (Sandbox Code Playgroud)
这个异构列表被推断为List[Any]就像在 Scala 2 中一样
然而以下
val x2 = List(List(1, 2), Vector("a", "b"))
Run Code Online (Sandbox Code Playgroud)
推断为 List[scala.collection.immutable.AbstractSeq[Int | String]]
这是相当混乱的行为。为什么Any在一种情况下会推断出两种不相交类型的 LUB ,而在另一种情况下会推断出联合类型?
如果这只是一个设计决定,是否有任何此类情况需要人们注意?
以下是三年多前的Macros: The Plan for Scala 3中的一段话:
例如,我们可以定义一个宏注释 @json,将 JSON 序列化器添加到一种类型中。
知道这在 Scala 3 中如何/是否可行吗?
更一般地说,Scala 3 中有什么可以提供“宏注释”功能吗?以下是宏注释 - Scala 2.13的引用:
与以前版本的宏天堂不同,2.0 中的宏注释在以下意义上是正确的:1) 不仅适用于类和对象,而且适用于任意定义,2)允许扩展类来修改甚至创建伴生对象
我的目标是将 Scala 3 代码作为字符串获取,并在运行时将其解析为 Scala 3 的抽象语法树。在这个过程中,如果代码有编译错误,我应该把它作为一些异常的一部分。更大的目标是,如果 Scala 代码有效,则以 Expr[T] 结束,并通过拼接正确的位来执行它(我已经介绍了这部分)。
这在 Scala 2.* 中是可行的,在这里使用 scala-reflect 。
val source =
"""
|object HelloWorld {
| def main(args: Array[String]): Unit = {
| println("Hello, world!")
| }
|}
|
|HelloWorld.main(Array())
|""".stripMargin
val tree = toolbox.parse(source)
val binary = toolbox.compile(tree)
binary()
Run Code Online (Sandbox Code Playgroud)
但据我推测,在 Scala 3 中,不会移植 scala-reflect。我如何在 Scala 3 中实现相同的目标?
鉴于:
abstract class Quantity[A <: Quantity[A]]
sealed trait UnitOfMeasure[A]
class Time extends Quantity[Time]
object Minutes extends UnitOfMeasure[Time]
class PowerRamp extends Quantity[PowerRamp]
object KilowattsPerHour extends UnitOfMeasure[PowerRamp]
type Test[X <: UnitOfMeasure[?]] = X match
case UnitOfMeasure[t] => t
Run Code Online (Sandbox Code Playgroud)
编译如下:
summon[Test[Minutes.type] =:= Time]
summon[Test[KilowattsPerHour.type] =:= PowerRamp]
Run Code Online (Sandbox Code Playgroud)
但是,如果UnitOfMeasure声明了trait :
sealed trait UnitOfMeasure[A <: Quantity[A]]
Run Code Online (Sandbox Code Playgroud)
两次传票都失败:
Cannot prove that Test[Minutes.type] =:= Time.
Note: a match type could not be fully reduced:
trying to reduce Test[Minutes.type]
failed since selector Minutes.type
matches none of the …Run Code Online (Sandbox Code Playgroud) 我试图找到一种简单而有效的方法来使用 Scala 3 来(反)序列化枚举circe。
考虑以下示例:
import io.circe.generic.auto._
import io.circe.syntax._
enum OrderType:
case BUY
case SELL
case class Order(id: Int, `type`: OrderType, amount: String)
val order = Order(1, OrderType.SELL, "123.4")
order.asJson
Run Code Online (Sandbox Code Playgroud)
序列化数据后,它变成
{
"id" : 1,
"type" : {
"SELL" : {
}
},
"amount" : "123.4"
}
Run Code Online (Sandbox Code Playgroud)
代替
{
"id" : 1,
"type" : "SELL",
"amount" : "123.4"
}
Run Code Online (Sandbox Code Playgroud)
这就是我想要的。
我知道我可以为此编写一个自定义(反)序列化器,它将解决这个特定实例的问题,如下所示:
implicit val encodeOrderType: Encoder[OrderType] = (a: OrderType) =>
Encoder.encodeString(a.toString)
implicit def decodeOrderType: Decoder[OrderType] = (c: HCursor) => …Run Code Online (Sandbox Code Playgroud) 如果我在 Scala 3 中有一个任意类型联合,是否可以编写一个从联合中“删除”一种类型的方法?
与 类似shapeless.ops.coproduct.Remove,但适用于本机 Scala 3。
例如,如果我有一个代表一些不同错误的联合类型,并且我想编写一个从一种特定错误类型中恢复的函数,并将其余错误保留为新的联合类型。
val result: Either[Foo | Bar | Baz | Bang, Thing]
val otherResult: Either[Foo | Bar, OtherThing]
// pretend syntax
def recoverBar[X, A](error: Bar | ...X)(f: Bar => A): Either[X, A] =
error match {
case e: Bar => Right(f(e))
case otherError => Left(otherError)
}
// example usage
val recoveredResult: Either[Foo | Baz | Bang, Option[Thing]] = result
.map { Option.apply }
.left.flatMap { recoverBar(_)(_ => None) }
val recoveredOther: …Run Code Online (Sandbox Code Playgroud) https://docs.scala-lang.org/scala3/reference/metaprogramming/compiletime-ops.html上的 Scala 3 参考文献提到了 Scala 3 mataprogramming 可能实现的一些“类似 Prolog 的编程风格”:
到目前为止的问题是,类似于 Prolog 的隐式搜索编程风格变得病毒式传播:一旦某个构造依赖于隐式搜索,它就必须被编写为逻辑程序本身。
但它们都保留了基于逻辑编程的隐式搜索程序的病毒性。
我做了一些搜索,但只知道它在某种程度上滥用了 Scala 编译时行为,并且其中的某些内容类似于 Prolog。
什么是“类似 Prolog 的编程风格”以及它是如何工作的?什么类似于Prolog?它在 Scala 3 中有效吗?
scala ×10
scala-3 ×10
dotty ×3
scala-macros ×2
circe ×1
function ×1
implicit ×1
macros ×1
prolog ×1
reflection ×1
symbols ×1
types ×1
union-types ×1