-
-
Notifications
You must be signed in to change notification settings - Fork 202
/
FilterIndex.scala
125 lines (104 loc) · 4.53 KB
/
FilterIndex.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package monocle.function
import monocle.{Iso, Traversal}
import scala.annotation.implicitNotFound
import scala.collection.immutable.SortedMap
import cats.syntax.traverse._
import cats.{Applicative, Order, Traverse}
import cats.instances.lazyList._
/** Typeclass that defines a [[Traversal]] from an `S` to all its elements `A` whose index `I` in `S` satisfies the
* predicate
* @tparam S
* source of [[Traversal]]
* @tparam I
* index
* @tparam A
* target of [[Traversal]], `A` is supposed to be unique for a given pair `(S, I)`
*/
@implicitNotFound(
"Could not find an instance of FilterIndex[${S},${I},${A}], please check Monocle instance location policy to " + "find out which import is necessary"
)
abstract class FilterIndex[S, I, A] extends Serializable {
def filterIndex(predicate: I => Boolean): Traversal[S, A]
}
trait FilterIndexFunctions {
def filterIndex[S, I, A](predicate: I => Boolean)(implicit ev: FilterIndex[S, I, A]): Traversal[S, A] =
ev.filterIndex(predicate)
}
object FilterIndex extends FilterIndexFunctions {
/** lift an instance of [[FilterIndex]] using an [[Iso]] */
def fromIso[S, A, I, B](iso: Iso[S, A])(implicit ev: FilterIndex[A, I, B]): FilterIndex[S, I, B] =
new FilterIndex[S, I, B] {
def filterIndex(predicate: I => Boolean): Traversal[S, B] =
iso.andThen(ev.filterIndex(predicate))
}
def fromTraverse[S[_]: Traverse, A](zipWithIndex: S[A] => S[(A, Int)]): FilterIndex[S[A], Int, A] =
new FilterIndex[S[A], Int, A] {
def filterIndex(predicate: Int => Boolean) =
new Traversal[S[A], A] {
def modifyA[F[_]: Applicative](f: A => F[A])(s: S[A]): F[S[A]] =
zipWithIndex(s).traverse { case (a, j) =>
if (predicate(j)) f(a) else Applicative[F].pure(a)
}
}
}
/** *********************************************************************************************
*/
/** Std instances */
/** *********************************************************************************************
*/
import cats.instances.list._
import cats.instances.vector._
implicit def listFilterIndex[A]: FilterIndex[List[A], Int, A] =
fromTraverse(_.zipWithIndex)
implicit def lazyListFilterIndex[A]: FilterIndex[LazyList[A], Int, A] =
fromTraverse(_.zipWithIndex)
implicit def mapFilterIndex[K, V]: FilterIndex[Map[K, V], K, V] =
new FilterIndex[Map[K, V], K, V] {
import cats.syntax.applicative._
import cats.syntax.functor._
def filterIndex(predicate: K => Boolean) =
new Traversal[Map[K, V], V] {
def modifyA[F[_]: Applicative](f: V => F[V])(s: Map[K, V]): F[Map[K, V]] =
s.toList
.traverse { case (k, v) =>
(if (predicate(k)) f(v) else v.pure[F]).tupleLeft(k)
}
.map(_.toMap)
}
}
implicit def sortedMapFilterIndex[K, V](implicit ok: Order[K]): FilterIndex[SortedMap[K, V], K, V] =
new FilterIndex[SortedMap[K, V], K, V] {
import cats.syntax.applicative._
import cats.syntax.functor._
def filterIndex(predicate: K => Boolean) =
new Traversal[SortedMap[K, V], V] {
def modifyA[F[_]: Applicative](f: V => F[V])(s: SortedMap[K, V]): F[SortedMap[K, V]] =
s.toList
.traverse { case (k, v) =>
(if (predicate(k)) f(v) else v.pure[F]).tupleLeft(k)
}
.map(kvs => SortedMap(kvs: _*)(ok.toOrdering))
}
}
implicit val stringFilterIndex: FilterIndex[String, Int, Char] =
new FilterIndex[String, Int, Char] {
def filterIndex(predicate: Int => Boolean) =
monocle.std.string.stringToList.andThen(FilterIndex.filterIndex[List[Char], Int, Char](predicate))
}
implicit def vectorFilterIndex[A]: FilterIndex[Vector[A], Int, A] =
fromTraverse(_.zipWithIndex)
/** *********************************************************************************************
*/
/** Cats instances */
/** *********************************************************************************************
*/
import cats.data.{Chain, NonEmptyChain, NonEmptyList, NonEmptyVector}
implicit def chainFilterIndex[A]: FilterIndex[Chain[A], Int, A] =
fromTraverse(_.zipWithIndex)
implicit def necFilterIndex[A]: FilterIndex[NonEmptyChain[A], Int, A] =
fromTraverse(_.zipWithIndex)
implicit def nelFilterIndex[A]: FilterIndex[NonEmptyList[A], Int, A] =
fromTraverse(_.zipWithIndex)
implicit def nevFilterIndex[A]: FilterIndex[NonEmptyVector[A], Int, A] =
fromTraverse(_.zipWithIndex)
}