gpt4 book ai didi

Scala:基于类型的列表分区

转载 作者:行者123 更新时间:2023-12-04 22:31:05 25 4
gpt4 key购买 nike

我有这个代码,我想改进:

sealed abstract class A
case class B() extends A
case class C() extends A
case class D() extends A

case class Foo[+T <: A](a: T)

/** Puts instances that match Foo(B()) in the first list and everything else,
* i.e. Foo(C()) and Foo(D()), in the second list. */
def partition(foos: List[Foo[_ <: A]]): (List[Foo[B]], List[Foo[_ <: A]]) = {
// ...
}

我想在以下几个方面进行改进:
  • 我可以更改 partition 的返回类型,以便它指出第二个列表中没有 Foo[B] 吗?
  • 我可以去掉 Foo 的类型参数 T (即将 Foo 更改为 case class Foo(a: A) )并仍然声明 partition 具有相同的类型保证吗? (显然,它必须返回与 (List[Foo], List[Foo]) 不同的东西。)

  • P.S.:让我知道“无形”标签是否与这个问题无关。

    最佳答案

    这个问题有点棘手,因为 Scala 混合了 algebraic data types (就像你的 A )和子类型。在大多数带有 ADT 的语言中, BCD 根本不是类型——它们只是“构造函数”(在某种意义上,与 OOP 构造函数相似但不相同)。

    在这些语言(如 Haskell 或 OCaml)中谈论 Foo[B] 是没有意义的,但在 Scala 中你可以,因为 Scala 将 ADT 实现为扩展基本特征或类的案例类(和类对象)。不过,这并不意味着您应该到处谈论 Foo[B] ,而且一般来说,如果您想用 FP 术语思考并利用类型系统来发挥您的优势,那么最好不要这样做。

    要回答您的具体问题:

  • 不,不是很方便。您可以使用带标签的联合(包含 Either[Foo[C], Foo[D]] 元素的列表)或类似 Shapeless 的 Coproduct(包含 Foo[C] :+: Foo[D] :+: CNil 元素的列表)来表示“A 类型的事物列表,但不是 B ”,但这两种方法对于某些事物来说都是相当繁重的机器这可能不是最好的主意。
  • 我建议不要在 Foo 的子类型上参数化 A ,但是如果您希望能够在类型级别表示“包含 FooB”,您将需要保留当前的方法。

  • 为了解决您的后记:如果您想对 ADT 进行概括,Shapeless 绝对适用——例如,请参阅我的博客文章 here 关于按构造函数进行分区。但是,如果您只为 A 执行此操作,Shapeless 可能不会给您带来太多好处。

    作为脚注,如果我真的需要一个分区操作来拆分 Foo[B] 类型的元素,我可能会这样写:
    def partition(foos: List[Foo[A]]): (List[Foo[B]], List[Foo[A]]) =
    foos.foldRight((List.empty[Foo[B]], List.empty[Foo[A]])) {
    case (Foo(B()), (bs, others)) => (Foo(B()) :: bs, others)
    case (other, (bs, others)) => (bs, other :: others)
    }

    这并不理想——如果我们真的想要一个 List[Foo[B]] ,最好有一个 List[Foo[~B]] 来表示剩余的东西——但这还不错。

    关于Scala:基于类型的列表分区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25222215/

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