【发布时间】:2020-09-03 15:28:52
【问题描述】:
我正在尝试查看是否有办法找到W2 类型,它是W 和E 两种类型的超类型。
在我的解决方案中,E 代表错误,W 代表警告。
我想要完成的是一个方法or,如果this 失败运行that 并将错误移动到警告类型。
这是我正在做的一个简化示例。
sealed trait Validator[-I, +E, +W, +A] extends Product with Serializable
这种类型有几种情况,在这里并不重要,所以我将介绍一个示例用法:
case class MyObj(coords: GeoCoords)
case class GeoCoords(lat: String, long: String)
// Getters
val getLatitude: Validator[GeoCoords, Nothing, Nothing, String] = from[GeoCoords].map(_.lat)
val getLongitude: Validator[GeoCoords, Nothing, Nothing, String] = from[GeoCoords].map(_.long)
val parseLatitude: Validator[GeoCoords, Exception, Nothing, Double] = getLatitude andThen nonEmptyString andThen convertToDouble
val parseLongitude: Validator[GeoCoords, Exception, Nothing, Double] = getLongitude andThen convertToDouble
现在这是一个不好的例子,但我想做的是因为parseLatitude 的错误类型为Exception,也许我想给出一个默认值,但仍然明白它失败了。我想将 Exception 从 E 错误参数移动到 W 警告参数,如下所示:
val defaultLatitude: Validator[GeoCoords, Nothing, Nothing, Double] = success(0)
val finalLatitude: Validator[GeoCoords, Nothing, Exception, Double] = parseLatitude or defaultLatitude
但是同样,如果不是提供默认值,我在or 之后采取的其他操作也可能会失败,因此也应该是这种情况:
val otherAction: Validator[GeoCoords, Throwable, Nothing, Double] = ???
val finalLatitude: Validator[GeoCoords, Throwable, Exception, Double] = parseLatitude or otherAction
我尝试在Validator 类型上以多种方式实现or,但每次它都会给我一个问题,基本上是一直到Any。
def or[I2 <: I, E2 >: E, W2 >: W, B >: A](that: Validator[I2, E2, W2, B]): Validator[I2, E2, W2, B] = Validator.conversion { (i: I2) =>
val aVal: Validator[Any, E, W, A] = this.run(i)
val bVal: Validator[Any, E2, W2, B] = that.run(i)
val a: Vector[W2] = aVal.warnings ++ bVal.warnings
// PROBLEM HERE
val b: Vector[Any] = a ++ aVal.errors
Result(
aVal.warnings ++ aVal.errors ++ bVal.warnings,
bVal.value.toRight(bVal.errors)
)
}
我需要能够说W2 是W 和E 的超类型,以便我可以将Vectors 连接在一起并在最后得到W2 类型。
一个超级简化的自包含示例是:
case class Example[+A, +B](a: List[A], b: List[B]) {
def or[A2 >: A, B2 >: B](that: Example[A2, B2]): Example[A2, Any] = {
Example(that.a, this.a ++ this.b ++ that.a)
}
}
object stackoverflow extends App {
val example1 = Example(List(1, 2), List(3, 4))
val example2 = Example(List(5, 6), List(7, 8))
val example3 = example1 or example2
}
我希望or 的输出类型为Example[A2, B2] 而不是Example[A2, Any]
【问题讨论】:
-
将警告和错误向上转换为同一类型真的有意义吗?后者如何区分它们?为什么不直接使用
List[Either[Warning, Error]]之类的东西?还是你自己的WarningOrErrorADT? -
这实际上是一个想法。我可能会这样做。不过,我仍然想知道是否有解决方法的答案,因为它对我来说变得更加好奇:)
-
@NigelBenns 请准备好MCVE(你没有提供
Validator、Result等的定义)。还请说明您编写的 3 个代码 sn-ps 有什么问题(您如何应用or,您如何检查 “Scala 将W2解析为Any”)。 “我想看看有没有办法找到一个类型W2,它是W和E两种类型的超类型” 请你说清楚你是什么正在努力实现?Any是任意W和E的超类型。什么是“ 超类型”? -
用用例更新了问题。如果需要,我可以尝试将事情简化为仅这些类型并提供完整的工作示例。
标签: scala typeclass covariance union-types