Scala:基于类型的列表分区
我有这个代码,我想改进:
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]吗? 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类型的列表”,但这两种方法都是相当重的机器,可能不是最好的想法. 为了解决你的后记:如果你想对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]]代表剩菜也很好 – 但它并不太糟糕. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |