Skip to content

Commit 4f2e30c

Browse files
refactor Cokleisli native closures to fix GC NPE
1 parent 5cc118f commit 4f2e30c

1 file changed

Lines changed: 124 additions & 66 deletions

File tree

core/src/main/scala/cats/data/Cokleisli.scala

Lines changed: 124 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -27,69 +27,81 @@ import cats.{CoflatMap, Comonad, Contravariant, Functor, Monad}
2727

2828
import scala.annotation.tailrec
2929

30-
/**
31-
* Represents a function `F[A] => B`.
32-
*/
30+
/** Represents a function `F[A] => B`.
31+
*/
3332
final case class Cokleisli[F[_], A, B](run: F[A] => B) { self =>
3433

35-
/**
36-
* Example:
37-
* {{{
38-
* scala> import cats._, data._
39-
* scala> val f = Cokleisli((xs: NonEmptyList[Int]) => xs.reverse.head)
40-
* scala> def before(x: Double) = x.toInt
41-
* scala> def after(x: Int) = x.toString
42-
* scala> f.dimap(before)(after).run(NonEmptyList.of(1.0,2.0))
43-
* res0: String = 2
44-
* }}}
45-
*/
46-
def dimap[C, D](f: C => A)(g: B => D)(implicit F: Functor[F]): Cokleisli[F, C, D] =
47-
Cokleisli(fc => g(run(F.map(fc)(f))))
48-
49-
/**
50-
* Example:
51-
* {{{
52-
* scala> import cats._, data._, implicits._
53-
* scala> val f = Cokleisli((xs: NonEmptyList[Int]) => xs.reverse.head)
54-
* scala> def before(x: Double) = x.toInt
55-
* scala> def after(x: Int) = x.toString
56-
* scala> f.lmap(before).rmap(after).run(NonEmptyList.of(1.0,2.0))
57-
* res0: String = 2
58-
* }}}
59-
*/
60-
def lmap[C](f: C => A)(implicit F: Functor[F]): Cokleisli[F, C, B] =
61-
Cokleisli(fc => run(F.map(fc)(f)))
34+
/** Example:
35+
* {{{
36+
* scala> import cats._, data._
37+
* scala> val f = Cokleisli((xs: NonEmptyList[Int]) => xs.reverse.head)
38+
* scala> def before(x: Double) = x.toInt
39+
* scala> def after(x: Int) = x.toString
40+
* scala> f.dimap(before)(after).run(NonEmptyList.of(1.0,2.0))
41+
* res0: String = 2
42+
* }}}
43+
*/
44+
def dimap[C, D](f: C => A)(g: B => D)(implicit
45+
F: Functor[F]
46+
): Cokleisli[F, C, D] = {
47+
val ev = F
48+
Cokleisli(fc => g(run(ev.map(fc)(f))))
49+
}
50+
51+
/** Example:
52+
* {{{
53+
* scala> import cats._, data._, implicits._
54+
* scala> val f = Cokleisli((xs: NonEmptyList[Int]) => xs.reverse.head)
55+
* scala> def before(x: Double) = x.toInt
56+
* scala> def after(x: Int) = x.toString
57+
* scala> f.lmap(before).rmap(after).run(NonEmptyList.of(1.0,2.0))
58+
* res0: String = 2
59+
* }}}
60+
*/
61+
def lmap[C](f: C => A)(implicit F: Functor[F]): Cokleisli[F, C, B] = {
62+
val ev = F
63+
Cokleisli(fc => run(ev.map(fc)(f)))
64+
}
6265

6366
def map[C](f: B => C): Cokleisli[F, A, C] =
6467
Cokleisli(fa => f(run(fa)))
6568

66-
/**
67-
* Example:
68-
* {{{
69-
* scala> import cats._, data._
70-
* scala> val sum = Cokleisli((xs: NonEmptyList[Int]) => xs.reduceLeft(_ + _))
71-
*
72-
* scala> sum.contramapValue((xs: NonEmptyList[String]) => xs.map(_.toInt)).run(NonEmptyList.of("1","2","3"))
73-
* res4: Int = 6
74-
* }}}
75-
*/
69+
/** Example:
70+
* {{{
71+
* scala> import cats._, data._
72+
* scala> val sum = Cokleisli((xs: NonEmptyList[Int]) => xs.reduceLeft(_ + _))
73+
*
74+
* scala> sum.contramapValue((xs: NonEmptyList[String]) => xs.map(_.toInt)).run(NonEmptyList.of("1","2","3"))
75+
* res4: Int = 6
76+
* }}}
77+
*/
7678
def contramapValue[C](f: F[C] => F[A]): Cokleisli[F, C, B] =
7779
Cokleisli(fc => run(f(fc)))
7880

7981
def flatMap[C](f: B => Cokleisli[F, A, C]): Cokleisli[F, A, C] =
8082
Cokleisli(fa => f(self.run(fa)).run(fa))
8183

82-
def compose[C](c: Cokleisli[F, C, A])(implicit F: CoflatMap[F]): Cokleisli[F, C, B] =
83-
Cokleisli(fc => run(F.coflatMap(fc)(c.run)))
84+
def compose[C](c: Cokleisli[F, C, A])(implicit
85+
F: CoflatMap[F]
86+
): Cokleisli[F, C, B] = {
87+
val ev = F
88+
Cokleisli(fc => run(ev.coflatMap(fc)(c.run)))
89+
}
8490

85-
def andThen[C](c: Cokleisli[F, B, C])(implicit F: CoflatMap[F]): Cokleisli[F, A, C] =
91+
def andThen[C](c: Cokleisli[F, B, C])(implicit
92+
F: CoflatMap[F]
93+
): Cokleisli[F, A, C] =
8694
c.compose(this)
8795

88-
def first[C](implicit F: Comonad[F]): Cokleisli[F, (A, C), (B, C)] =
89-
Cokleisli(fac => run(F.map(fac)(_._1)) -> F.extract(F.map(fac)(_._2)))
96+
def first[C](implicit F: Comonad[F]): Cokleisli[F, (A, C), (B, C)] = {
97+
val ev = F
98+
Cokleisli(fac => run(ev.map(fac)(_._1)) -> ev.extract(ev.map(fac)(_._2)))
99+
}
90100

91-
def second[C](implicit F: Comonad[F]): Cokleisli[F, (C, A), (C, B)] =
92-
Cokleisli(fca => F.extract(F.map(fca)(_._1)) -> run(F.map(fca)(_._2)))
101+
def second[C](implicit F: Comonad[F]): Cokleisli[F, (C, A), (C, B)] = {
102+
val ev = F
103+
Cokleisli(fca => ev.extract(ev.map(fca)(_._1)) -> run(ev.map(fca)(_._2)))
104+
}
93105
}
94106

95107
object Cokleisli extends CokleisliInstances {
@@ -107,28 +119,40 @@ sealed abstract private[data] class CokleisliInstances extends CokleisliInstance
107119
implicit def catsDataMonadForCokleisli[F[_], A]: Monad[Cokleisli[F, A, *]] =
108120
new CokleisliMonad[F, A]
109121

110-
implicit def catsDataMonoidKForCokleisli[F[_]](implicit ev: Comonad[F]): MonoidK[λ[α => Cokleisli[F, α, α]]] =
122+
implicit def catsDataMonoidKForCokleisli[F[_]](implicit
123+
ev: Comonad[F]
124+
): MonoidK[λ[α => Cokleisli[F, α, α]]] =
111125
Category[Cokleisli[F, *, *]].algebraK
112126
}
113127

114128
sealed abstract private[data] class CokleisliInstances0 extends CokleisliInstances1 {
115-
implicit def catsDataArrowForCokleisli[F[_]](implicit ev: Comonad[F]): Arrow[Cokleisli[F, *, *]] =
129+
implicit def catsDataArrowForCokleisli[F[_]](implicit
130+
ev: Comonad[F]
131+
): Arrow[Cokleisli[F, *, *]] =
116132
new CokleisliArrow[F] { def F: Comonad[F] = ev }
117133
}
118134

119135
sealed abstract private[data] class CokleisliInstances1 {
120-
implicit def catsDataComposeForCokleisli[F[_]](implicit ev: CoflatMap[F]): Compose[Cokleisli[F, *, *]] =
136+
implicit def catsDataComposeForCokleisli[F[_]](implicit
137+
ev: CoflatMap[F]
138+
): Compose[Cokleisli[F, *, *]] =
121139
new CokleisliCompose[F] { def F: CoflatMap[F] = ev }
122140

123-
implicit def catsDataProfunctorForCokleisli[F[_]](implicit ev: Functor[F]): Profunctor[Cokleisli[F, *, *]] =
141+
implicit def catsDataProfunctorForCokleisli[F[_]](implicit
142+
ev: Functor[F]
143+
): Profunctor[Cokleisli[F, *, *]] =
124144
new CokleisliProfunctor[F] { def F: Functor[F] = ev }
125145

126-
implicit def catsDataSemigroupKForCokleisli[F[_]](implicit ev: CoflatMap[F]): SemigroupK[λ[α => Cokleisli[F, α, α]]] =
146+
implicit def catsDataSemigroupKForCokleisli[F[_]](implicit
147+
ev: CoflatMap[F]
148+
): SemigroupK[λ[α => Cokleisli[F, α, α]]] =
127149
Compose[Cokleisli[F, *, *]].algebraK
128150

129151
implicit def catsDataContravariantForCokleisli[F[_]: Functor, A]: Contravariant[Cokleisli[F, *, A]] =
130152
new Contravariant[Cokleisli[F, *, A]] {
131-
def contramap[B, C](fbc: Cokleisli[F, B, A])(f: C => B): Cokleisli[F, C, A] = fbc.lmap(f)
153+
def contramap[B, C](fbc: Cokleisli[F, B, A])(
154+
f: C => B
155+
): Cokleisli[F, C, A] = fbc.lmap(f)
132156
}
133157
}
134158

@@ -139,13 +163,19 @@ private[data] class CokleisliMonad[F[_], A]
139163
def pure[B](x: B): Cokleisli[F, A, B] =
140164
Cokleisli.pure(x)
141165

142-
def flatMap[B, C](fa: Cokleisli[F, A, B])(f: B => Cokleisli[F, A, C]): Cokleisli[F, A, C] =
166+
def flatMap[B, C](fa: Cokleisli[F, A, B])(
167+
f: B => Cokleisli[F, A, C]
168+
): Cokleisli[F, A, C] =
143169
fa.flatMap(f)
144170

145-
override def map[B, C](fa: Cokleisli[F, A, B])(f: B => C): Cokleisli[F, A, C] =
171+
override def map[B, C](fa: Cokleisli[F, A, B])(
172+
f: B => C
173+
): Cokleisli[F, A, C] =
146174
fa.map(f)
147175

148-
def tailRecM[B, C](b: B)(fn: B => Cokleisli[F, A, Either[B, C]]): Cokleisli[F, A, C] =
176+
def tailRecM[B, C](
177+
b: B
178+
)(fn: B => Cokleisli[F, A, Either[B, C]]): Cokleisli[F, A, C] =
149179
Cokleisli { (fa: F[A]) =>
150180
@tailrec
151181
def loop(c: Cokleisli[F, A, Either[B, C]]): C =
@@ -164,38 +194,66 @@ private trait CokleisliArrow[F[_]]
164194
with CokleisliProfunctor[F] {
165195
implicit def F: Comonad[F]
166196

167-
def lift[A, B](f: A => B): Cokleisli[F, A, B] =
168-
Cokleisli(fa => f(F.extract(fa)))
197+
def lift[A, B](f: A => B): Cokleisli[F, A, B] = {
198+
val ev = F
199+
Cokleisli(fa => f(ev.extract(fa)))
200+
}
169201

170202
def first[A, B, C](fa: Cokleisli[F, A, B]): Cokleisli[F, (A, C), (B, C)] =
171203
fa.first[C]
172204

173-
override def second[A, B, C](fa: Cokleisli[F, A, B]): Cokleisli[F, (C, A), (C, B)] =
205+
override def second[A, B, C](
206+
fa: Cokleisli[F, A, B]
207+
): Cokleisli[F, (C, A), (C, B)] =
174208
fa.second[C]
175209

176-
override def dimap[A, B, C, D](fab: Cokleisli[F, A, B])(f: C => A)(g: B => D): Cokleisli[F, C, D] =
210+
override def dimap[A, B, C, D](fab: Cokleisli[F, A, B])(f: C => A)(
211+
g: B => D
212+
): Cokleisli[F, C, D] =
177213
super[CokleisliProfunctor].dimap(fab)(f)(g)
178214

179-
override def split[A, B, C, D](f: Cokleisli[F, A, B], g: Cokleisli[F, C, D]): Cokleisli[F, (A, C), (B, D)] =
180-
Cokleisli(fac => f.run(F.map(fac)(_._1)) -> g.run(F.map(fac)(_._2)))
215+
override def split[A, B, C, D](
216+
f: Cokleisli[F, A, B],
217+
g: Cokleisli[F, C, D]
218+
): Cokleisli[F, (A, C), (B, D)] = {
219+
val ev = F
220+
Cokleisli(fac => f.run(ev.map(fac)(_._1)) -> g.run(ev.map(fac)(_._2)))
221+
}
222+
223+
override def merge[A, B, C](
224+
f: Cokleisli[F, A, B],
225+
g: Cokleisli[F, A, C]
226+
): Cokleisli[F, A, (B, C)] = {
227+
val ev = F
228+
Cokleisli(fa => f.run(fa) -> g.run(fa))
229+
}
181230
}
182231

183232
private trait CokleisliCompose[F[_]] extends Compose[Cokleisli[F, *, *]] {
184233
implicit def F: CoflatMap[F]
185234

186-
def compose[A, B, C](f: Cokleisli[F, B, C], g: Cokleisli[F, A, B]): Cokleisli[F, A, C] =
235+
def compose[A, B, C](
236+
f: Cokleisli[F, B, C],
237+
g: Cokleisli[F, A, B]
238+
): Cokleisli[F, A, C] =
187239
f.compose(g)
188240
}
189241

190242
private trait CokleisliProfunctor[F[_]] extends Profunctor[Cokleisli[F, *, *]] {
191243
implicit def F: Functor[F]
192244

193-
def dimap[A, B, C, D](fab: Cokleisli[F, A, B])(f: C => A)(g: B => D): Cokleisli[F, C, D] =
245+
def dimap[A, B, C, D](fab: Cokleisli[F, A, B])(f: C => A)(
246+
g: B => D
247+
): Cokleisli[F, C, D] =
194248
fab.dimap(f)(g)
195249

196-
override def lmap[A, B, C](fab: Cokleisli[F, A, B])(f: C => A): Cokleisli[F, C, B] =
250+
override def lmap[A, B, C](fab: Cokleisli[F, A, B])(
251+
f: C => A
252+
): Cokleisli[F, C, B] =
197253
fab.lmap(f)
198254

199-
override def rmap[A, B, C](fab: Cokleisli[F, A, B])(f: B => C): Cokleisli[F, A, C] =
255+
override def rmap[A, B, C](fab: Cokleisli[F, A, B])(
256+
f: B => C
257+
): Cokleisli[F, A, C] =
200258
fab.map(f)
201259
}

0 commit comments

Comments
 (0)