gpt4 book ai didi

scala - 使用代码生成(如 Scala Meta)来抓取样板文件

转载 作者:行者123 更新时间:2023-12-03 07:26:46 25 4
gpt4 key购买 nike

我使用 Shapeless 的标记类型来获得良好的类型安全原语以通过我的业务逻辑。定义这些类型从一个简单的开始:

sealed trait MyTaggedStringTag
type MyTaggedString = String @@ MyTaggedStringTag

但是我为此添加了一些辅助逻辑,现在我的定义看起来更像:

sealed trait MyTaggedStringTag

type MyTaggedString = String @@ MyTaggedStringTag
object MyTaggedString {
def fromString(untaggedMyTaggedString: String): MyTaggedString = {
val myTaggedString = tag[MyTaggedStringTag](untaggedMyTaggedString)
myTaggedString
}
}
implicit class MyTaggedStringOps(val myTaggedString: MyTaggedString) extends AnyVal { def untagged = myTaggedString.asInstanceOf[String] }

因此,每个定义都有很多样板文件。我真的很想能够通过执行以下操作来生成它:

@tagged[String] type MyTaggedString

有没有办法用 Scala Meta 或其他代码生成工具来做这样的事情?

最佳答案

已更新

现在可以正常使用了,可以在我称之为 Taggy 的新库中看到.这是宏的最新版本:

class tagged extends scala.annotation.StaticAnnotation {
inline def apply(defn: Any): Any = meta {
// Macro annotation type and value parameters come back as AST data, not
// values, and are accessed by destructuring `this`.
defn match {
case q"..$mods type $newType = ${underlyingType: Type.Name}" =>
TaggedImpl.expand(underlyingType, newType, mods)
case _ =>
abort("Correct usage: @tagged type NewType = UnderlyingType" )
}
}
}

object TaggedImpl {
def expand(underlyingType: Type.Name, newType: Type.Name, mods: Seq[Mod]) = {
// Shapeless needs a phantom type to join with the underlying type to
// create our tagged type. Ideally should never leak to external code.
val tag = Type.Name(newType.value + "Tag")

// The `fromX` helper will go in the companion object.
val companionObject = Term.Name(newType.value)

// We'll name the `fromX` method based on the underlying type.
val fromMethod = Term.Name("from" + underlyingType.value)

// The `untagged` helper goes in an implicit class, since the tagged type
// is only a type alias, and can't have real methods.
val opsClass = Type.Name(newType.value + "Ops")

q"""
sealed trait $tag
..$mods type $newType = com.acjay.taggy.tag.@@[$underlyingType, $tag]
..$mods object $companionObject {
def $fromMethod(untagged: $underlyingType): $newType = {
val tagged = com.acjay.taggy.tag[$tag](untagged)
tagged
}
}
..$mods implicit class $opsClass(val tagged: $newType) extends AnyVal {
def untagged = tagged.asInstanceOf[$underlyingType]
def modify(f: $underlyingType => $underlyingType) = $companionObject.$fromMethod(f(untagged))
}
"""
}
}

object tag {
def apply[U] = new Tagger[U]

trait Tagged[U]
type @@[+T, U] = T with Tagged[U]

class Tagger[U] {
def apply[T](t : T) : T @@ U = t.asInstanceOf[T @@ U]
}
}

为了便于阅读,宏语法的解析和代码生成是分开的。您可以将 TaggedImpl.expand 内联到 meta block 中。另请注意,此处的语法现在是 @tagged type MyTaggedString = String

原始答案

我把它作为概念证明工作。但它采用底层类型的字符串名称:

import scala.meta._

class tagged(_underlyingTypeName: String) extends scala.annotation.StaticAnnotation {
inline def apply(defn: Any): Any = meta {
// Can't figure out how to do this extraction as a quasiquote, so I
// figured out exactly the AST `this` produces to extract the string
// parameter.
val Term.New(
Template(
List(),
List(Term.Apply(Ctor.Ref.Name("tagged"), List(Lit.String(underlyingTypeName)))),
Term.Param(List(), Name.Anonymous(), None, None),
None
)
) = this

val q"..$mods type $tname[..$tparams]" = defn
val underlyingType = Type.Name(underlyingTypeName)
TaggedImpl.expand(tname, underlyingType)
}
}

object TaggedImpl {
def expand(taggedType: Type.Name, underlyingType: Type.Name) = {
val tag = Type.Name(taggedType.value + "Tag")
val companionObject = Term.Name(taggedType.value)
val fromMethodName = Term.Name("from" + underlyingType.value)
val opsClass = Type.Name(taggedType.value + "Ops")

q"""
sealed trait $tag
type $taggedType = shapeless.tag.@@[$underlyingType, $tag]
object $companionObject {
def $fromMethodName(untagged: $underlyingType): $taggedType = {
val tagged = shapeless.tag[$tag](untagged)
tagged
}
}
implicit class $opsClass(val tagged: $taggedType) extends AnyVal {
def untagged = tagged.asInstanceOf[$underlyingType]
}
"""
}
}

关于scala - 使用代码生成(如 Scala Meta)来抓取样板文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46005321/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com