加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Scala:基于类型的列表分区

发布时间:2020-12-16 18:22:40 所属栏目:安全 来源:网络整理
导读:我有这个代码,我想改进: sealed abstract class Acase class B() extends Acase class C() extends Acase class D() extends Acase class Foo[+T : A](a: T)/** Puts instances that match Foo(B()) in the first list and everything else,* i.e. Foo(C())
我有这个代码,我想改进:

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]]) = {
  // ...
}

我想在以下方面对此进行改进:

>我可以更改分区的返回类型,以便它表明第二个列表中没有Foo [B]吗?
>我可以摆脱Foo的类型参数T(即将Foo更改为案例类Foo(a:A))并仍然声明具有相同类型保证的分区吗? (显然,它必须返回不同于(List [Foo],List [Foo])的东西.)

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

解决方法

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

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

回答您的具体问题:

>不,不是以任何方便的方式.您可以使用带标记的并集(带有[Foo [C],Foo [D]]元素的列表)或类似Shapeless的Coproduct(带有Foo [C] :: Foo [D] :: CNil元素的列表)来表示“A类型的列表,但不是B类型的列表”,但这两种方法都是相当重的机器,可能不是最好的想法.
>我建议不要在A的子类型上参数化Foo,但如果您希望能够在类型级别表示“包含B的Foo”,那么您将需要保留当前的方法.

为了解决你的后记:如果你想对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,others)) => (bs,other :: others)
  }

这不是理想的 – 如果我们真的想要一个List [Foo [B]],那么有一个List [Foo [~B]]代表剩菜也很好 – 但它并不太糟糕.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读