Skip to content

Commit

Permalink
Remove Applicative#pureEval
Browse files Browse the repository at this point in the history
This probably resolves #1150, though it doesn't provide an alternative
type class as was brought up there.

@adelbertc has [gotten tripped up](#1150 (comment)) by `pureEval` defaulting to a call to `pure` with `.value` called on the `Eval`.

@johnynek has also [questioned](#1150 (comment)) `pureEval` being directly on `Applicative`.

@tpolecat has [raised concerns](https://gitter.im/typelevel/cats?at=5794dc4c1b9de56c0edd887a) that `pureEval` looks like it might exist as a way to inject
side effects into a type, but that it doesn't actually make any claims
about execution semantics or value retention, so it can't be relied upon
to do this.

I think that there could be an argument for having an instantiation method for
a side-effect-y type (like a `Task`) that takes an `Eval[A]` and produces an instance
that will repeat the computation given `Always`, memoize the value given
`Later`, etc. However, I don't think that @tpolecat necessarily agrees
with me, and I think that even _if_ this is a reasonable thing to do,
`Applicative` probably isn't the place for it.

Since several people have questioned `pureEval`, it was entirely
untested, and I haven't heard any one argue for it staying, I'm inclined
to remove it. If someone has a compelling example of when a non-strict
argument can be useful for `pure`, then I may be convinced. But even
then we should clearly document what behavior can be expected of
`pureEval`.
  • Loading branch information
ceedubs committed Jul 27, 2016
1 parent a2d8f60 commit 94fcf03
Show file tree
Hide file tree
Showing 6 changed files with 0 additions and 26 deletions.
7 changes: 0 additions & 7 deletions core/src/main/scala/cats/Applicative.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,6 @@ import simulacrum.typeclass
*/
def pure[A](x: A): F[A]

/**
* `pureEval` lifts any value into the Applicative Functor.
*
* This variant supports optional laziness.
*/
def pureEval[A](x: Eval[A]): F[A] = pure(x.value)

override def map[A, B](fa: F[A])(f: A => B): F[B] =
ap(pure(f))(fa)

Expand Down
1 change: 0 additions & 1 deletion core/src/main/scala/cats/Eval.scala
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,6 @@ private[cats] trait EvalInstances extends EvalInstances0 {
new Bimonad[Eval] with MonadRec[Eval] {
override def map[A, B](fa: Eval[A])(f: A => B): Eval[B] = fa.map(f)
def pure[A](a: A): Eval[A] = Now(a)
override def pureEval[A](la: Eval[A]): Eval[A] = la
def flatMap[A, B](fa: Eval[A])(f: A => Eval[B]): Eval[B] = fa.flatMap(f)
def extract[A](la: Eval[A]): A = la.value
def coflatMap[A, B](fa: Eval[A])(f: Eval[A] => B): Eval[B] = Later(f(fa))
Expand Down
5 changes: 0 additions & 5 deletions core/src/main/scala/cats/instances/future.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,6 @@ trait FutureInstances extends FutureInstances1 {
new FutureCoflatMap with MonadError[Future, Throwable]{
def pure[A](x: A): Future[A] = Future.successful(x)

override def pureEval[A](x: Eval[A]): Future[A] = x match {
case Now(x) => Future.successful(x)
case _ => Future(x.value)
}

def flatMap[A, B](fa: Future[A])(f: A => Future[B]): Future[B] = fa.flatMap(f)

def handleErrorWith[A](fea: Future[A])(f: Throwable => Future[A]): Future[A] = fea.recoverWith { case t => f(t) }
Expand Down
5 changes: 0 additions & 5 deletions core/src/main/scala/cats/instances/try.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ trait TryInstances extends TryInstances1 {
new TryCoflatMap with MonadError[Try, Throwable] with Traverse[Try] with MonadRec[Try] {
def pure[A](x: A): Try[A] = Success(x)

override def pureEval[A](x: Eval[A]): Try[A] = x match {
case Now(x) => Success(x)
case _ => Try(x.value)
}

override def product[A, B](ta: Try[A], tb: Try[B]): Try[(A, B)] = (ta, tb) match {
case (Success(a), Success(b)) => Success((a, b))
case (f: Failure[_], _) => castFailure[(A, B)](f)
Expand Down
5 changes: 0 additions & 5 deletions core/src/main/scala/cats/syntax/applicative.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,8 @@ package syntax

trait ApplicativeSyntax {
implicit def catsSyntaxApplicativeId[A](a: A): ApplicativeIdOps[A] = new ApplicativeIdOps[A](a)
implicit def catsSyntaxApplicativeEval[A](a: Eval[A]): ApplicativeEvalOps[A] = new ApplicativeEvalOps[A](a)
}

final class ApplicativeIdOps[A](val a: A) extends AnyVal {
def pure[F[_]](implicit F: Applicative[F]): F[A] = F.pure(a)
}

final class ApplicativeEvalOps[A](val a: Eval[A]) extends AnyVal {
def pureEval[F[_]](implicit F: Applicative[F]): F[A] = F.pureEval(a)
}
3 changes: 0 additions & 3 deletions tests/src/test/scala/cats/tests/SyntaxTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,6 @@ class SyntaxTests extends AllInstances with AllSyntax {
def testApplicative[F[_]: Applicative, A]: Unit = {
val a = mock[A]
val fa = a.pure[F]

val la = mock[Eval[A]]
val lfa = la.pureEval[F]
}

def testApplicativeError[F[_, _], E, A](implicit F: ApplicativeError[F[E, ?], E]): Unit = {
Expand Down

0 comments on commit 94fcf03

Please sign in to comment.