Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace ~> with NaturalTransformation #991

Merged
merged 1 commit into from May 17, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/arrow/NaturalTransformation.scala
Expand Up @@ -14,8 +14,8 @@ trait NaturalTransformation[F[_], G[_]] extends Serializable { self =>
def andThen[H[_]](f: NaturalTransformation[G, H]): NaturalTransformation[F, H] =
f.compose(self)

def or[H[_]](h: H ~> G): Coproduct[F, H, ?] ~> G =
new (Coproduct[F, H, ?] ~> G) {
def or[H[_]](h: NaturalTransformation[H,G]): NaturalTransformation[Coproduct[F, H, ?],G] =
new (NaturalTransformation[Coproduct[F, H, ?],G]) {
def apply[A](fa: Coproduct[F, H, A]): G[A] = fa.run match {
case Xor.Left(ff) => self(ff)
case Xor.Right(gg) => h(gg)
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/data/Kleisli.scala
@@ -1,7 +1,7 @@
package cats
package data

import cats.arrow.{Arrow, Choice, Split}
import cats.arrow.{Arrow, Choice, Split, NaturalTransformation}
import cats.functor.{Contravariant, Strong}

/**
Expand Down Expand Up @@ -48,7 +48,7 @@ final case class Kleisli[F[_], A, B](run: A => F[B]) { self =>
def local[AA](f: AA => A): Kleisli[F, AA, B] =
Kleisli(f.andThen(run))

def transform[G[_]](f: F ~> G): Kleisli[G, A, B] =
def transform[G[_]](f: NaturalTransformation[F,G]): Kleisli[G, A, B] =
Kleisli(a => f(run(a)))

def lower(implicit F: Applicative[F]): Kleisli[F, A, F[B]] =
Expand Down
7 changes: 5 additions & 2 deletions docs/src/main/tut/freemonad.md
Expand Up @@ -165,12 +165,15 @@ DSL. By itself, this DSL only represents a sequence of operations

To do this, we will use a *natural transformation* between type
containers. Natural transformations go between types like `F[_]` and
`G[_]` (this particular transformation would be written as `F ~> G`).
`G[_]` (this particular transformation would be written as
`NaturalTransformation[F,G]` or as done here using the symbolic
alternative as `F ~> G`).
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is the note in the tutorial


In our case, we will use a simple mutable map to represent our key
value store:

```tut:silent
import cats.arrow.NaturalTransformation
import cats.{Id, ~>}
import scala.collection.mutable

Expand Down Expand Up @@ -241,7 +244,7 @@ recursive structure by:
This operation is called `Free.foldMap`:

```scala
final def foldMap[M[_]](f: S ~> M)(M: Monad[M]): M[A] = ...
final def foldMap[M[_]](f: NaturalTransformation[S,M])(M: Monad[M]): M[A] = ...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The build is failing because ~> is imported, but NaturalTransformation is not. We should probably pick either one or the other for the tutorial and stick to it, but I do like your note about one being an alias for the other.

```

`M` must be a `Monad` to be flattenable (the famous monoid aspect
Expand Down
4 changes: 3 additions & 1 deletion free/src/main/scala/cats/free/Coyoneda.scala
@@ -1,6 +1,8 @@
package cats
package free

import cats.arrow.NaturalTransformation

/**
* The dual view of the Yoneda lemma. Also a free functor on `F`.
* This is isomorphic to `F` as long as `F` itself is a functor.
Expand Down Expand Up @@ -36,7 +38,7 @@ sealed abstract class Coyoneda[F[_], A] extends Serializable { self =>
final def map[B](f: A => B): Aux[F, B, Pivot] =
apply(fi)(f compose k)

final def transform[G[_]](f: F ~> G): Aux[G, A, Pivot] =
final def transform[G[_]](f: NaturalTransformation[F,G]): Aux[G, A, Pivot] =
apply(f(fi))(k)

}
Expand Down
7 changes: 3 additions & 4 deletions free/src/main/scala/cats/free/Free.scala
Expand Up @@ -130,7 +130,7 @@ sealed abstract class Free[S[_], A] extends Product with Serializable {
* Run to completion, mapping the suspension with the given transformation at each step and
* accumulating into the monad `M`.
*/
final def foldMap[M[_]](f: S ~> M)(implicit M: Monad[M]): M[A] =
final def foldMap[M[_]](f: NaturalTransformation[S,M])(implicit M: Monad[M]): M[A] =
step match {
case Pure(a) => M.pure(a)
case Suspend(s) => f(s)
Expand All @@ -142,14 +142,13 @@ sealed abstract class Free[S[_], A] extends Product with Serializable {
* using the given natural transformation.
* Be careful if your natural transformation is effectful, effects are applied by mapSuspension.
*/
final def mapSuspension[T[_]](f: S ~> T): Free[T, A] =
final def mapSuspension[T[_]](f: NaturalTransformation[S,T]): Free[T, A] =
foldMap[Free[T, ?]] {
new NaturalTransformation[S, Free[T, ?]] {
def apply[B](fa: S[B]): Free[T, B] = Suspend(f(fa))
}
}(Free.freeMonad)

final def compile[T[_]](f: S ~> T): Free[T, A] = mapSuspension(f)
final def compile[T[_]](f: NaturalTransformation[S,T]): Free[T, A] = mapSuspension(f)

}

8 changes: 4 additions & 4 deletions free/src/main/scala/cats/free/FreeApplicative.scala
Expand Up @@ -27,7 +27,7 @@ sealed abstract class FreeApplicative[F[_], A] extends Product with Serializable
/** Interprets/Runs the sequence of operations using the semantics of Applicative G
* Tail recursive only if G provides tail recursive interpretation (ie G is FreeMonad)
*/
final def foldMap[G[_]](f: F ~> G)(implicit G: Applicative[G]): G[A] =
final def foldMap[G[_]](f: NaturalTransformation[F,G])(implicit G: Applicative[G]): G[A] =
this match {
case Pure(a) => G.pure(a)
case Ap(pivot, fn) => G.map2(f(pivot), fn.foldMap(f))((a, g) => g(a))
Expand All @@ -40,16 +40,16 @@ sealed abstract class FreeApplicative[F[_], A] extends Product with Serializable
foldMap(NaturalTransformation.id[F])

/** Interpret this algebra into another FreeApplicative */
final def compile[G[_]](f: F ~> G): FA[G, A] =
final def compile[G[_]](f: NaturalTransformation[F,G]): FA[G, A] =
foldMap[FA[G, ?]] {
new NaturalTransformation[F, FA[G, ?]] {
def apply[B](fa: F[B]): FA[G, B] = lift(f(fa))
}
}

/** Interpret this algebra into a Monoid */
final def analyze[M:Monoid](f: F ~> λ[α => M]): M =
foldMap[Const[M, ?]](new (F ~> Const[M, ?]) {
final def analyze[M:Monoid](f: NaturalTransformation[F,λ[α => M]]): M =
foldMap[Const[M, ?]](new (NaturalTransformation[F,Const[M, ?]]) {
def apply[X](x: F[X]): Const[M,X] = Const(f(x))
}).getConst

Expand Down
4 changes: 2 additions & 2 deletions free/src/test/scala/cats/free/FreeApplicativeTests.scala
Expand Up @@ -97,7 +97,7 @@ class FreeApplicativeTests extends CatsSuite {

type Tracked[A] = State[String, A]

val f: Foo ~> Tracked = new (Foo ~> Tracked) {
val f: NaturalTransformation[Foo,Tracked] = new NaturalTransformation[Foo,Tracked] {
def apply[A](fa: Foo[A]): Tracked[A] = State[String, A]{ s0 =>
(s0 + fa.toString + ";", fa.getA)
}
Expand All @@ -120,7 +120,7 @@ class FreeApplicativeTests extends CatsSuite {

val z = Apply[Dsl].map2(x, y)((_, _) => ())

val asString: Id ~> λ[α => String] = new (Id ~> λ[α => String]) {
val asString: NaturalTransformation[Id,λ[α => String]] = new NaturalTransformation[Id,λ[α => String]] {
def apply[A](a: A): String = a.toString
}

Expand Down
4 changes: 2 additions & 2 deletions free/src/test/scala/cats/free/FreeTests.scala
Expand Up @@ -56,7 +56,7 @@ class FreeTests extends CatsSuite {
z <- if (j<10000) a(j) else Free.pure[FTestApi, Int](j)
} yield z

def runner: FTestApi ~> Id = new (FTestApi ~> Id) {
def runner: NaturalTransformation[FTestApi,Id] = new NaturalTransformation[FTestApi,Id] {
def apply[A](fa: FTestApi[A]): Id[A] = fa match {
case TB(i) => i+1
}
Expand All @@ -77,7 +77,7 @@ object FreeTests extends FreeTestsInstances {
}

sealed trait FreeTestsInstances {
val headOptionU: List ~> Option = new (List ~> Option) {
val headOptionU: NaturalTransformation[List,Option] = new NaturalTransformation[List,Option] {
def apply[A](fa: List[A]): Option[A] = fa.headOption
}

Expand Down
7 changes: 4 additions & 3 deletions free/src/test/scala/cats/free/InjectTests.scala
@@ -1,6 +1,7 @@
package cats
package free

import cats.arrow.NaturalTransformation
import cats.tests.CatsSuite
import cats.data.{Xor, Coproduct}
import org.scalacheck._
Expand Down Expand Up @@ -39,19 +40,19 @@ class InjectTests extends CatsSuite {
implicit def test2Arbitrary[A](implicit seqArb: Arbitrary[Int], intAArb : Arbitrary[Int => A]): Arbitrary[Test2[A]] =
Arbitrary(for {s <- seqArb.arbitrary; f <- intAArb.arbitrary} yield Test2(s, f))

object Test1Interpreter extends (Test1Algebra ~> Id) {
object Test1Interpreter extends NaturalTransformation[Test1Algebra,Id] {
override def apply[A](fa: Test1Algebra[A]): Id[A] = fa match {
case Test1(k, h) => h(k)
}
}

object Test2Interpreter extends (Test2Algebra ~> Id) {
object Test2Interpreter extends NaturalTransformation[Test2Algebra,Id] {
override def apply[A](fa: Test2Algebra[A]): Id[A] = fa match {
case Test2(k, h) => h(k)
}
}

val coProductInterpreter: T ~> Id = Test1Interpreter or Test2Interpreter
val coProductInterpreter: NaturalTransformation[T,Id] = Test1Interpreter or Test2Interpreter

val x: Free[T, Int] = Free.inject[Test1Algebra, T](Test1(1, identity))

Expand Down
4 changes: 2 additions & 2 deletions tests/src/test/scala/cats/tests/KleisliTests.scala
@@ -1,7 +1,7 @@
package cats
package tests

import cats.arrow.{Arrow, Choice, Split}
import cats.arrow.{Arrow, Choice, Split, NaturalTransformation}
import cats.data.{XorT, Kleisli, Reader}
import cats.functor.{Contravariant, Strong}
import cats.laws.discipline._
Expand Down Expand Up @@ -126,7 +126,7 @@ class KleisliTests extends CatsSuite {

test("transform") {
val opt = Kleisli { (x: Int) => Option(x.toDouble) }
val optToList = new (Option ~> List) { def apply[A](fa: Option[A]): List[A] = fa.toList }
val optToList = new NaturalTransformation[Option,List] { def apply[A](fa: Option[A]): List[A] = fa.toList }
val list = opt.transform(optToList)

val is = 0.to(10).toList
Expand Down
Expand Up @@ -28,11 +28,11 @@ class NaturalTransformationTests extends CatsSuite {

case class Test2[A](v : A) extends Test2Algebra[A]

object Test1NT extends (Test1Algebra ~> Id) {
object Test1NT extends NaturalTransformation[Test1Algebra,Id] {
override def apply[A](fa: Test1Algebra[A]): Id[A] = fa.v
}

object Test2NT extends (Test2Algebra ~> Id) {
object Test2NT extends NaturalTransformation[Test2Algebra,Id] {
override def apply[A](fa: Test2Algebra[A]): Id[A] = fa.v
}

Expand Down