如何确保(在编译时)该集合未重新排序?

时间:2015-08-04 06:28:59

标签: scala scalaz type-safety

假设我已编入索引集合(ListMap并不重要):

val zipped = List(1 -> "A", 3 -> "C", 8 -> "D")

很难使用(因为每个操作,如map,必须处理index),所以我想传递给业务处理程序的是:

case class Indexed[T](seq: Seq[T], i: Seq[Int])

val unzipped = Indexed(List("A", "C", "D"), List(1,3,8))

handler(unzipped.seq)

但我需要限制用户,仅限mapfiltercollectcontainsforallscanLeft和等等。但不是flatMapfilter除外),sort++等等。所以任何双射/射击,但不是注射。在紧要关头,用户可以在没有filter / flatMap的情况下生活,因此Functor而不是Monad对我来说可能没问题 - 无论如何我可以接受List[Option[T]] => List[T]原始要求不完整MonadM[M[T]] => M[T]T => M[T])。

toListtoSet是可以接受的,但我也想确保返回(来自业务处理程序)集合基于原始集合。我可以通过向原始集合的类型签名添加依赖于路径的Tag(路径依赖类型)并且需要具有相同标记的集合作为返回类型(可以仅使用asInstanceOf作弊)来执行此操作。通过实现我自己的Traversable可以满足我的第一个要求。

所以我自己的“轮子”来解决这个只是一个包装器(只允许操作子集+标签以确保集合相同):

 trait NonReorderedListT {
     trait Tag
 }

 trait NonReorderedList[Tg <: NonReorderedListT#Tag, T] {
   type Tag = Tg 
   def map[U](f: T => U): NonReorderedList[Tag, U] //same tag
   //... other permitted operations should be here        
 }


 object NonReorderedList {

   class NonReorderedListImpl[Tg <: NonReorderedListT#Tag, T] private[NonReorderedList] (l: List[T]) extends NonReorderedList[Tg, T] { 
      def map[U](f: T => U) = new NonReorderedListImpl[Tag, U](l.map(f))
      //... other permitted operations should be here  
   }     


   def apply[T](l: List[T]) = {
     val tagC = new NonReorderedListT {} //container
     new NonReorderedListImpl[tagC.Tag, T](l)
   }
 }

以下是Scala REPL的结果:

defined trait NonReorderedListT
defined trait NonReorderedList
defined class NonReorderedListImpl
defined object NonReorderedList

scala>  val l = NonReorderedList(List(1,2,3))
warning: there was one feature warning; re-run with -feature for details
l: NonReorderedListImpl[tagC.Tag,Int] forSome { val tagC: NonReorderedListT } = NonReorderedListImpl@3620eab

scala> val res: NonReorderedList[l.Tag, Int] = l.map(_ + 1)
res: NonReorderedList[l.Tag,Int] = NonReorderedListImpl@34bddf43

scala>  val m = NonReorderedList(List(1,2,3))
warning: there was one feature warning; re-run with -feature for details
m: NonReorderedListImpl[tagC.Tag,Int] forSome { val tagC: NonReorderedListT } = NonReorderedListImpl@2d8c729f

scala> val res: NonReorderedList[l.Tag, Int] = m.map(_ + 1)
<console>:31: error: type mismatch;
 found   : NonReorderedListImpl[m.Tag,Int]
    (which expands to)  NonReorderedListImpl[tagC.Tag,Int]
 required: NonReorderedList[l.Tag,Int]
    (which expands to)  NonReorderedList[tagC.Tag,Int]
       val res: NonReorderedList[l.Tag, Int] = m.map(_ + 1)
                                                    ^

但是,当你需要这样的集合时,情况应该不是那么罕见,所以Scalaz可能已经有了一些实现,比如NonEmptylist,但是NonReorderedList

我正在做这一切,因为我有一个已订购的集合(1 - &gt;“A”,2 - “B”,3 - &gt;“C”,4 - &gt;“D”,5 - &gt; ;“E”)作为输入,分成(1 - >“A”,3 - >“C”,4 - &gt;“D”)和(2 - &gt;“B”,5 - &gt; ;“E”),它们被单独处理然后合并(原始顺序应该保留)。使用复杂谓词进行排序需要一些时间(因为它调用外部服务),所以我不能只用它重新排序两次 - 第二次重新排序应该基于简单的索引。

P.S。我不是在寻找更少的类型安全的替代品,因为我已经在我的项目中有这样的:)。我的目标是改进现有的(在我的项目中)代码。

1 个答案:

答案 0 :(得分:1)

也许这可以通过使用NatHList来实现无形的?我们的想法是明确地为元素的索引建模。 (我问了一个相关的问题Achieving compile safe indexing with Shapeless。)例如,

import shapeless._
import Nat._

case class Entry[+N<:Nat](value: String, index: N)

val send: Entry[ _1] :: Entry[ _3] :: Entry[ _4] :: HNil= Entry("A", _1):: Entry("C", _3) :: Entry("D", _4) :: HNil
val keep= Entry("B", _2) :: Entry("E", _5)  :: HNil

这会提供某种类型的安全性(虽然我不确定性能影响。)