gpt4 book ai didi

scala - 给定方法参数返回最具体的类型

转载 作者:行者123 更新时间:2023-12-04 18:00:52 26 4
gpt4 key购买 nike

我正在尝试给定一些可变参数创建一个特定且独特的类型。

下面列出了代表前四个自然数的预定义类型(使用类似 HList 的方法 Digit0..Digit9、DimensionCons 和 EndDimension(如 HNil))。

  object Defined {
type D1 = DimensionCons[Digit1, EndDimension.type]
val d1 = DimensionCons(Digit1(), EndDimension)

type D2 = DimensionCons[Digit2, EndDimension.type]
val d2 = DimensionCons(Digit2(), EndDimension)

type D3 = DimensionCons[Digit3, EndDimension.type]
val d3 = DimensionCons(Digit3(), EndDimension)

type D4 = DimensionCons[Digit4, EndDimension.type]
val d4 = DimensionCons(Digit4(), EndDimension)
}

我正在寻找一种带有指示签名的方法,例如
  def getDimensionTpe[D <: Dimension](dim: Int) : D

例如返回 DimensionCons[Digit2, EndDimension.type]getDimensionTpe(2) .

问题:
  • 如果没有白盒宏(生成类型?),这是否可能?如果是这样,如何处理以及处理什么?
  • 是否有可能或适用的替代技术?
  • 路径依赖类型有帮助吗?

  • 谢谢,马丁

    最佳答案

    我不确定我是否理解你到底在做什么 DimensionConsDigitN业务,但可以使用 Shapeless 编写一个方法,该方法将接受一个整数(尽管只是一个文字常量——它必须在编译时知道)并让该整数确定返回值的静态类型。

    为了简化代码以获得完整的工作示例,假设我们要编写如下所示的方法:

    trait Dimension
    case class Dim1() extends Dimension
    case class Dim2() extends Dimension
    case class Dim3() extends Dimension
    // And so on...

    def getDimensionTpe[D <: Dimension](dim: Int) : D

    ...哪里 getDimensionTpe(1)会返回 Dim1() (静态输入为 Dim1 ), getDimensionTpe(2)会返回 Dim2()等。为此,我们可以引入无形状自然数和维度之间的类型类映射:
    import shapeless.{ DepFn0, Nat }

    trait DimMap[N <: Nat] extends DepFn0 {
    type Out <: Dimension
    }

    object DimMap {
    type Aux[N <: Nat, D <: Dimension] = DimMap[N] { type Out = D }

    implicit val dimMap1: Aux[Nat._1, Dim1] = new DimMap[Nat._1] {
    type Out = Dim1
    def apply(): Dim1 = Dim1()
    }

    implicit val dimMap2: Aux[Nat._2, Dim2] = new DimMap[Nat._2] {
    type Out = Dim2
    def apply(): Dim2 = Dim2()
    }

    implicit val dimMap3: Aux[Nat._3, Dim3] = new DimMap[Nat._3] {
    type Out = Dim3
    def apply(): Dim3 = Dim3()
    }

    // And so on as needed.
    }

    如果您的维度类型有更多结构,则可以避免此处的样板文件,但我不清楚您的 DigitN 是如何设置的。东西正在工作。不过,这似乎与问题的要点是正交的,关于如何定义 getDimensionTpe .

    如果您不介意编写一个白盒宏,您可以将其定义为具有类似于以下签名的内容:
    def getDimensionTpe[D <: Dimension](dim: Int) : D

    但是,这是一个巨大的痛苦,Shapeless 让您无需自定义宏即可编写基本相同的内容。鉴于 DimMap上面的类型类,你可以写如下:
    def getDimensionTpe(dim: Nat)(implicit m: DimMap[dim.N]) : m.Out = m()

    进而:
    scala> val d1: Dim1 = getDimensionTpe(1)
    d1: Dim1 = Dim1()

    scala> val d2: Dim2 = getDimensionTpe(2)
    d2: Dim2 = Dim2()

    scala> val d3: Dim3 = getDimensionTpe(3)
    d3: Dim3 = Dim3()

    如果你弄错了静态类型,编译器会告诉你:
    scala> val d3: Dim1 = getDimensionTpe(3)
    <console>:15: error: type mismatch;
    found : DimMap.dimMap3.Out
    (which expands to) Dim3
    required: Dim1
    val d3: Dim1 = getDimensionTpe(3)
    ^

    如果你提供一个没有映射的整数文字,那也是一个编译时错误:
    scala> getDimensionTpe(0)
    <console>:14: error: could not find implicit value for parameter m: DimMap[shapeless._0]
    getDimensionTpe(0)
    ^

    最后,如果您提供 Int不是整数文字的参数,您还会收到编译器错误:
    scala> val x = 1
    x: Int = 1

    scala> getDimensionTpe(x)
    <console>:16: error: Expression x does not evaluate to a non-negative Int literal
    getDimensionTpe(x)
    ^

    在幕后,Shapeless 正在使用一个宏来实现这一点,它甚至没有那么可怕——您可以阅读 the NatMacros definition详情。

    关于scala - 给定方法参数返回最具体的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54151207/

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