11package aecor .data
22
33import aecor .data .Folded .{ Impossible , Next }
4+ import cats .kernel .Eq
5+ import cats .{
6+ Alternative ,
7+ Applicative ,
8+ CoflatMap ,
9+ Eval ,
10+ Monad ,
11+ MonadCombine ,
12+ MonadError ,
13+ Now ,
14+ Show ,
15+ TraverseFilter
16+ }
17+
18+ import scala .annotation .tailrec
419
520sealed abstract class Folded [+ A ] extends Product with Serializable {
621 def fold [B ](impossible : => B , next : A => B ): B = this match {
@@ -19,10 +34,25 @@ sealed abstract class Folded[+A] extends Product with Serializable {
1934 case Impossible => that
2035 case Next (a) => a
2136 }
37+ def orElse [AA >: A ](that : Folded [AA ]): Folded [AA ] = this match {
38+ case Next (_) => this
39+ case Impossible => that
40+ }
41+ def isNext : Boolean = fold(false , _ => true )
42+ def isImpossible : Boolean = ! isNext
43+
44+ def filter (f : A => Boolean ): Folded [A ] = this match {
45+ case Next (a) if f(a) => this
46+ case _ => Impossible
47+ }
48+ def exists (f : A => Boolean ): Boolean = filter(f).isNext
49+ def forall (f : A => Boolean ): Boolean = fold(true , f)
50+
51+ def toOption : Option [A ] = fold(None , Some (_))
2252}
23- object Folded {
24- private final case object Impossible extends Folded [Nothing ]
25- private final case class Next [+ A ](a : A ) extends Folded [A ]
53+ object Folded extends FoldedInstances {
54+ final case object Impossible extends Folded [Nothing ]
55+ final case class Next [+ A ](a : A ) extends Folded [A ]
2656 def impossible [A ]: Folded [A ] = Impossible
2757 def next [A ](a : A ): Folded [A ] = Next (a)
2858 object syntax {
@@ -32,3 +62,107 @@ object Folded {
3262 def impossible [A ]: Folded [A ] = Folded .impossible
3363 }
3464}
65+
66+ trait FoldedInstances {
67+ implicit val aecorDataInstancesForFolded
68+ : TraverseFilter [Folded ] with MonadError [Folded , Unit ] with MonadCombine [Folded ] with Monad [
69+ Folded
70+ ] with CoflatMap [Folded ] with Alternative [Folded ] =
71+ new TraverseFilter [Folded ] with MonadError [Folded , Unit ] with MonadCombine [Folded ]
72+ with Monad [Folded ] with CoflatMap [Folded ] with Alternative [Folded ] {
73+
74+ def empty [A ]: Folded [A ] = Impossible
75+
76+ def combineK [A ](x : Folded [A ], y : Folded [A ]): Folded [A ] = x orElse y
77+
78+ def pure [A ](x : A ): Folded [A ] = Next (x)
79+
80+ override def map [A , B ](fa : Folded [A ])(f : A => B ): Folded [B ] =
81+ fa.map(f)
82+
83+ def flatMap [A , B ](fa : Folded [A ])(f : A => Folded [B ]): Folded [B ] =
84+ fa.flatMap(f)
85+
86+ @ tailrec
87+ def tailRecM [A , B ](a : A )(f : A => Folded [Either [A , B ]]): Folded [B ] =
88+ f(a) match {
89+ case Impossible => Impossible
90+ case Next (Left (a1)) => tailRecM(a1)(f)
91+ case Next (Right (b)) => Next (b)
92+ }
93+
94+ override def map2 [A , B , Z ](fa : Folded [A ], fb : Folded [B ])(f : (A , B ) => Z ): Folded [Z ] =
95+ fa.flatMap(a => fb.map(b => f(a, b)))
96+
97+ override def map2Eval [A , B , Z ](fa : Folded [A ],
98+ fb : Eval [Folded [B ]])(f : (A , B ) => Z ): Eval [Folded [Z ]] =
99+ fa match {
100+ case Impossible => Now (Impossible )
101+ case Next (a) => fb.map(_.map(f(a, _)))
102+ }
103+
104+ def coflatMap [A , B ](fa : Folded [A ])(f : Folded [A ] => B ): Folded [B ] =
105+ if (fa.isNext) Next (f(fa)) else Impossible
106+
107+ def foldLeft [A , B ](fa : Folded [A ], b : B )(f : (B , A ) => B ): B =
108+ fa match {
109+ case Impossible => b
110+ case Next (a) => f(b, a)
111+ }
112+
113+ def foldRight [A , B ](fa : Folded [A ], lb : Eval [B ])(f : (A , Eval [B ]) => Eval [B ]): Eval [B ] =
114+ fa match {
115+ case Impossible => lb
116+ case Next (a) => f(a, lb)
117+ }
118+
119+ def raiseError [A ](e : Unit ): Folded [A ] = Impossible
120+
121+ def handleErrorWith [A ](fa : Folded [A ])(f : (Unit ) => Folded [A ]): Folded [A ] = fa orElse f(())
122+
123+ def traverseFilter [G [_], A , B ](
124+ fa : Folded [A ]
125+ )(f : A => G [Option [B ]])(implicit G : Applicative [G ]): G [Folded [B ]] =
126+ fa match {
127+ case Impossible => G .pure(Impossible )
128+ case Next (a) =>
129+ G .map(f(a)) {
130+ case Some (aa) => Next (aa)
131+ case None => Impossible
132+ }
133+ }
134+
135+ override def traverse [G [_]: Applicative , A , B ](fa : Folded [A ])(f : A => G [B ]): G [Folded [B ]] =
136+ fa match {
137+ case Impossible => Applicative [G ].pure(Impossible )
138+ case Next (a) => Applicative [G ].map(f(a))(Next (_))
139+ }
140+
141+ override def filter [A ](fa : Folded [A ])(p : A => Boolean ): Folded [A ] =
142+ fa.filter(p)
143+
144+ override def exists [A ](fa : Folded [A ])(p : A => Boolean ): Boolean =
145+ fa.exists(p)
146+
147+ override def forall [A ](fa : Folded [A ])(p : A => Boolean ): Boolean =
148+ fa.forall(p)
149+
150+ override def isEmpty [A ](fa : Folded [A ]): Boolean =
151+ fa.isImpossible
152+ }
153+
154+ implicit def aecorDataShowForFolded [A ](implicit A : Show [A ]): Show [Folded [A ]] =
155+ new Show [Folded [A ]] {
156+ def show (fa : Folded [A ]): String = fa match {
157+ case Next (a) => s " Next( ${A .show(a)}) "
158+ case Impossible => " Impossible"
159+ }
160+ }
161+
162+ implicit def aecorDataEqForFolded [A ](implicit A : Eq [A ]): Eq [Folded [A ]] =
163+ Eq .instance {
164+ case (Next (l), Next (r)) => A .eqv(l, r)
165+ case (Impossible , Impossible ) => true
166+ case _ => false
167+ }
168+ }
0 commit comments