[ all classes ]
[ lzwpack.data ]
Coverage Summary for Class: ListVectorInstances (lzwpack.data)
| Class | Method, % | Line, % |
|---|---|---|
| ListVectorInstances | 77.8% (7/ 9) | 77.8% (7/ 9) |
| ListVectorInstances$$anon$1 | 100% (3/ 3) | 100% (3/ 3) |
| ListVectorInstances$$anon$2 | 100% (3/ 3) | 100% (3/ 3) |
| ListVectorInstances$$anonfun$ListVectorEq$2 | 100% (1/ 1) | 100% (1/ 1) |
| ListVectorInstances$ListVectorApplicative$ | 100% (3/ 3) | 100% (3/ 3) |
| ListVectorInstances$ListVectorTraverse$ | 100% (4/ 4) | 100% (6/ 6) |
| total | 91.3% (21/ 23) | 92% (23/ 25) |
1 package lzwpack.data
2
3 import cats.{Applicative, Eq, Eval, Monoid, Show, Traverse, ~>}
4 import lzwpack.data.ListVector.empty
5 import cats.implicits._
6 import cats.kernel.Hash
7
8 import scala.collection.{GenTraversable, TraversableLike}
9 import scala.collection.generic.{IsSeqLike, IsTraversableLike}
10
11 /**
12 * Defines some generic type class instances for [[ListVector]].
13 */
14 trait ListVectorInstances {
15 implicit object ListVectorTraverse extends Traverse[ListVector] {
16 override def traverse[F[_]: Applicative, A, B](fa: ListVector[A])(f: A => F[B]): F[ListVector[B]] =
17 fa.foldLeft(empty[B].pure[F])((acc, a) => acc.map2(f(a))(_ + _))
18
19 override def foldLeft[A, B](fa: ListVector[A], b: B)(f: (B, A) => B): B =
20 fa.foldLeft(b)(f)
21
22 /**
23 * Lazy right fold. Using [[cats.Eval]] is enforced by the typeclass, but it allows us to short-circuit some
24 * folds if necessary.
25 */
26 override def foldRight[A, B](fa: ListVector[A], init: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = fa match {
27 case h :: t => f(h, Eval.defer(foldRight(t, init)(f)))
28 case _ => init
29 }
30 }
31
32 /**
33 * ListVector forms a monoid for all A types. It's more useful to have a Monoid instance
34 * available than a MonoidK given the functionality is the same for both instances.
35 */
36 implicit def ListVectorMonoid[A]: Monoid[ListVector[A]] = new Monoid[ListVector[A]] {
37 override def empty: ListVector[A] = ListVector.empty[A]
38
39 override def combine(as0: ListVector[A], as1: ListVector[A]): ListVector[A] =
40 as0 concat as1
41 }
42
43 implicit object ListVectorApplicative extends Applicative[ListVector] {
44 override def pure[A](x: A): ListVector[A] = ListVector(x)
45
46 override def ap[A, B](ff: ListVector[A => B])(fa: ListVector[A]): ListVector[B] =
47 ff foldMap (fa map _)
48 }
49
50 implicit def ListVectorShow[A: Show]: Show[ListVector[A]] = { as =>
51 s"ListVector(${as.map(_.show).intercalate(", ")})"
52 }
53
54 implicit def ListVectorHash[A: Hash]: Hash[ListVector[A]] = new Hash[ListVector[A]] {
55 override def hash(x: ListVector[A]): Int = x.hashCode
56
57 override def eqv(x: ListVector[A], y: ListVector[A]): Boolean = ListVectorEq[A].eqv(x, y)
58 }
59
60 /**
61 * Strict equality for two list vectors. The implementation is O(n) as we
62 * go through each of the list elements and compare them.
63 *
64 * @note Could be implemented with foldRight
65 */
66 implicit def ListVectorEq[A: Eq]: Eq[ListVector[A]] = { (as, bs) =>
67 @annotation.tailrec
68 def iter(as: ListVector[A], bs: ListVector[A]): Boolean =
69 if (as.isEmpty && bs.isEmpty) true else as.head === bs.head && iter(as.tail, bs.tail)
70
71 // If the sizes are the same and the hash codes are the same then check individual elements
72 as.size == bs.size && as.hashCode == bs.hashCode && iter(as, bs)
73 }
74
75 implicit def toSeq[A](as: ListVector[A]): Seq[A] = as.toSeq
76 }