Scala中的通用递归类型

Posted

技术标签:

【中文标题】Scala中的通用递归类型【英文标题】:Generic recursive type in Scala 【发布时间】:2021-10-14 04:03:35 【问题描述】:

刚开始接触 Scala,现在想了解是否有任何方法可以在 Scala 中表达 Deep 部分类型(递归类型)?

######################更新#################### #

我想要实现的是采用现有的案例类并以某种方式对其进行“版本化”,以便它递归地将其添加到每个字段,即使是在深度嵌套的级别

例如假设我定义了这些类

case class A(p1: Int, p2: Int, ..)
case class B(p1: Map[String, A])
case class C(param1: String, param2: String, param3: Option[B]) 

我想要version C,这意味着对于每个参数类型(递归)我想要添加一个可选的version: Int

我知道,最天真的方法是定义一个新类 VersionedValue,然后手动重新定义所有现有类型以适应它。

例如它可能是什么样子

case class VersionedValue [A](value: A, version: Option[Int])

case class A(p1: VersionedValue[Int], p2: VersionedValue[Int])

case class B(p1: Map[String, VersionedValue[A]])

case class C(p1: VersionedValue[String], 
             p2: VersionedValue[String],
             p3: Option[B]) 

############################################## #####

使用 TypeScript 已经有一段时间了,通常看起来像这样:

/** 
* the VersionedDeepPartial<T> will recursively iterate through 
* each of the "keys" (or attributes) and for each creates a new
* object that adds a version field. The value attribute will hold 
* what was originally the type for the key.
*/
export type VersionedDeepPartial<T> = 
  [P in keyof T]?: value: VersionedDeepPartial<T[P]>; version?:number
;

// So if I had an interface (in typescript) looking like:

interface A 
  p1: number,
  p2: number,


interface B 
   [key: string]: A


interface C 
   p1: String,
   p2: String,
   p3: B


/**
* Note that interface C does not define any versioning attribute to
* its fields. But by wrapping the type within the 
*/
VersionedDeepPartial<T>

const partialFoo: VersionedDeepPartial<C> = 
    p1:  value: "asdf", version: 1 ,
    p2:  value: "asdf" ,
    p3: 
        "somekey": 
           p1: value: 1, version: 1,
           p2: value: 2
    
 

基本上,我想要的是通过递归现有类型/类定义并“注入”版本来定义一个新类型。

我已经阅读/浏览了有关此主题的解释,但没有成功。这可以用 Scala 表达吗?

【问题讨论】:

我认为这需要宏或无形之类的库。想知道 Scala 3 中是否有任何特性可以用来实现这一点(Mirror?)。 我很好奇你想用这个解决什么问题?我怀疑在 Scala 中有更好的静态类型解决问题的方法。 Scala 中有递归类型,但由于我们很多人看不懂 TS,可能值得多解释一下这些代码的作用,以便我们更好地帮助您 嘿,稍微更新一下文本以使其更清晰@JackLeow @texasbruce ^ TS 代码,尤其是 DeepPartial 类型定义是一种有效地使现有类型中的每个属性成为可选的方法。然后,这允许您实例化或验证类型的部分数据。对于我的用例,我想避免复制粘贴我的复杂类型存在的类型定义。因为这在 TS 中几乎可以实现,但在 scala 中还没有找到方法 【参考方案1】:

您可能需要更高种类的数据方法:

case class HKDA[F[_]](p1: F[Int], p2: F[Int], ..)
case class HKDB[F[_]](p1: Map[String, HKDA[F]])
case class HKDC[F[_]](param1: F[String], param2: F[String], param3: Option[HKDB[F]])

type Id[A] = A
type A = HKDA[Id]
type B = HKDB[Id]
type C = HKDC[Id]

case class Versioned[A](a: A, version: Int)
type VersionedA = HKDA[Versioned]
type VersionedB = HKDB[Versioned]
type VersionedC = HKDC[Versioned]

【讨论】:

以上是关于Scala中的通用递归类型的主要内容,如果未能解决你的问题,请参考以下文章

在scala中读取csv的通用类

通用优先级队列中的协变和逆变类型

Scala在通用特征方法中找不到案例类参数

Scala中变量声明中的通用通配符

Scala,spray-json:通用枚举 json 格式

如何将包含参数的案例类与通用类型匹配