从任意类型的联合中删除一种类型的类型级别

发布于 2025-02-12 13:14:19 字数 936 浏览 0 评论 0原文

如果我在Scala 3中有一个任意类型的联盟,是否可以编写一种从联盟中“删除”一种类型的方法?

类似于shapeless.opp.coduct.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: Either[Foo, OtherThing] = otherResult
  .left.flatMap { recoverBar(_)(_ => OtherThing.default) }

即某种类型的通用方法

[Foo | Bar | Baz | Bang] =>> [Foo | Baz | Bang]
[Foo | Bar] =>> [Foo]
[Bar] =>> [Nothing]

If I have an arbitrary type union in Scala 3, is it possible to write a method that "removes" one type from the union?

Similar to shapeless.ops.coproduct.Remove, but for native Scala 3.

For example, if I have a union type representing a handful of different errors, and I want to write a function that recovers from one specific error type and leave the remaining errors as a new union type.

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: Either[Foo, OtherThing] = otherResult
  .left.flatMap { recoverBar(_)(_ => OtherThing.default) }

I.e. some kind of type-level generic way to do

[Foo | Bar | Baz | Bang] =>> [Foo | Baz | Bang]
[Foo | Bar] =>> [Foo]
[Bar] =>> [Nothing]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

自找没趣 2025-02-19 13:14:19

您可以使用typeTest

class Remove[A]:
  def apply[B](aOrB: A | B)(using tt: TypeTest[A | B, A]): Either[A, B] =
    aOrB match
      case a: A => Left(a)
      case b    => Right(b.asInstanceOf[B])

def remove[A]: Remove[A] = Remove[A]

type Foo = Boolean | Int | String
val foo: Foo = "foo"

val noInt = remove[Int](foo)

// It inferred the correct type:
val inferred: Either[Int, Boolean | String] = noInt

// And we get the expected value: Right(foo)
println(noInt) 

匹配无法推断另一种情况必须是b,但我认为这是我们可以做的最好的,这很糟糕。目前。

You can do it with a TypeTest:

class Remove[A]:
  def apply[B](aOrB: A | B)(using tt: TypeTest[A | B, A]): Either[A, B] =
    aOrB match
      case a: A => Left(a)
      case b    => Right(b.asInstanceOf[B])

def remove[A]: Remove[A] = Remove[A]

type Foo = Boolean | Int | String
val foo: Foo = "foo"

val noInt = remove[Int](foo)

// It inferred the correct type:
val inferred: Either[Int, Boolean | String] = noInt

// And we get the expected value: Right(foo)
println(noInt) 

It kinda sucks that the match is unable to infer that the other case must be a B but I think this is the best we can do for now.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文