Skip to content

Commit

Permalink
Merge pull request #1072 from peterneyens/rename-natural-transformati…
Browse files Browse the repository at this point in the history
…on-functionk

Rename NaturalTransformation to FunctionK.
  • Loading branch information
ceedubs committed May 31, 2016
2 parents 6c6b2a8 + 8509cd4 commit 92269f7
Show file tree
Hide file tree
Showing 16 changed files with 90 additions and 91 deletions.
31 changes: 31 additions & 0 deletions core/src/main/scala/cats/arrow/FunctionK.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package cats
package arrow

import cats.data.{Xor, Coproduct}

trait FunctionK[F[_], G[_]] extends Serializable { self =>
def apply[A](fa: F[A]): G[A]

def compose[E[_]](f: FunctionK[E, F]): FunctionK[E, G] =
new FunctionK[E, G] {
def apply[A](fa: E[A]): G[A] = self.apply(f(fa))
}

def andThen[H[_]](f: FunctionK[G, H]): FunctionK[F, H] =
f.compose(self)

def or[H[_]](h: FunctionK[H,G]): FunctionK[Coproduct[F, H, ?], G] =
new FunctionK[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)
}
}
}

object FunctionK {
def id[F[_]]: FunctionK[F, F] =
new FunctionK[F, F] {
def apply[A](fa: F[A]): F[A] = fa
}
}
31 changes: 0 additions & 31 deletions core/src/main/scala/cats/arrow/NaturalTransformation.scala

This file was deleted.

10 changes: 5 additions & 5 deletions core/src/main/scala/cats/data/Coproduct.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cats
package data

import cats.arrow.NaturalTransformation
import cats.arrow.FunctionK
import cats.functor.Contravariant

/** `F` on the left and `G` on the right of [[Xor]].
Expand Down Expand Up @@ -63,13 +63,13 @@ final case class Coproduct[F[_], G[_], A](run: F[A] Xor G[A]) {
*
* Example:
* {{{
* scala> import cats.arrow.NaturalTransformation
* scala> import cats.arrow.FunctionK
* scala> import cats.data.Coproduct
* scala> val listToOption =
* | new NaturalTransformation[List, Option] {
* | new FunctionK[List, Option] {
* | def apply[A](fa: List[A]): Option[A] = fa.headOption
* | }
* scala> val optionToOption = NaturalTransformation.id[Option]
* scala> val optionToOption = FunctionK.id[Option]
* scala> val cp1: Coproduct[List, Option, Int] = Coproduct.leftc(List(1,2,3))
* scala> val cp2: Coproduct[List, Option, Int] = Coproduct.rightc(Some(4))
* scala> cp1.fold(listToOption, optionToOption)
Expand All @@ -78,7 +78,7 @@ final case class Coproduct[F[_], G[_], A](run: F[A] Xor G[A]) {
* res1: Option[Int] = Some(4)
* }}}
*/
def fold[H[_]](f: NaturalTransformation[F, H], g: NaturalTransformation[G, H]): H[A] =
def fold[H[_]](f: FunctionK[F, H], g: FunctionK[G, H]): H[A] =
run.fold(f.apply, g.apply)
}

Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/data/Kleisli.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cats
package data

import cats.arrow.{Arrow, Choice, Split, NaturalTransformation}
import cats.arrow.{Arrow, Choice, Split, FunctionK}
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: NaturalTransformation[F,G]): Kleisli[G, A, B] =
def transform[G[_]](f: FunctionK[F,G]): Kleisli[G, A, B] =
Kleisli(a => f(run(a)))

def lower(implicit F: Applicative[F]): Kleisli[F, A, F[B]] =
Expand Down
3 changes: 1 addition & 2 deletions core/src/main/scala/cats/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import cats.data.Xor
*/
package object cats {

type ~>[F[_], G[_]] = arrow.NaturalTransformation[F, G]
type <~[F[_], G[_]] = arrow.NaturalTransformation[G, F]
type ~>[F[_], G[_]] = arrow.FunctionK[F, G]

type = Nothing
type = Any
Expand Down
10 changes: 5 additions & 5 deletions docs/src/main/tut/freeapplicative.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ at this point. To make our program useful we need to interpret it.

```tut:silent
import cats.Id
import cats.arrow.NaturalTransformation
import cats.arrow.FunctionK
import cats.std.function._
// a function that takes a string as input
type FromString[A] = String => A
val compiler =
new NaturalTransformation[ValidationOp, FromString] {
new FunctionK[ValidationOp, FromString] {
def apply[A](fa: ValidationOp[A]): String => A =
str =>
fa match {
Expand Down Expand Up @@ -103,7 +103,7 @@ import scala.concurrent.ExecutionContext.Implicits.global
type ParValidator[A] = Kleisli[Future, String, A]
val parCompiler =
new NaturalTransformation[ValidationOp, ParValidator] {
new FunctionK[ValidationOp, ParValidator] {
def apply[A](fa: ValidationOp[A]): ParValidator[A] =
Kleisli { str =>
fa match {
Expand All @@ -130,7 +130,7 @@ import cats.std.list._
type Log[A] = Const[List[String], A]
val logCompiler =
new NaturalTransformation[ValidationOp, Log] {
new FunctionK[ValidationOp, Log] {
def apply[A](fa: ValidationOp[A]): Log[A] =
fa match {
case Size(size) => Const(List(s"size >= $size"))
Expand Down Expand Up @@ -166,7 +166,7 @@ import cats.data.Prod
type ValidateAndLog[A] = Prod[ParValidator, Log, A]
val prodCompiler =
new NaturalTransformation[ValidationOp, ValidateAndLog] {
new FunctionK[ValidationOp, ValidateAndLog] {
def apply[A](fa: ValidationOp[A]): ValidateAndLog[A] = {
fa match {
case Size(size) =>
Expand Down
8 changes: 4 additions & 4 deletions docs/src/main/tut/freemonad.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,14 +166,14 @@ 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
`NaturalTransformation[F,G]` or as done here using the symbolic
`FunctionK[F,G]` or as done here using the symbolic
alternative as `F ~> G`).

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

```tut:silent
import cats.arrow.NaturalTransformation
import cats.arrow.FunctionK
import cats.{Id, ~>}
import scala.collection.mutable
Expand Down Expand Up @@ -244,7 +244,7 @@ recursive structure by:
This operation is called `Free.foldMap`:

```scala
final def foldMap[M[_]](f: NaturalTransformation[S,M])(M: Monad[M]): M[A] = ...
final def foldMap[M[_]](f: FunctionK[S,M])(M: Monad[M]): M[A] = ...
```

`M` must be a `Monad` to be flattenable (the famous monoid aspect
Expand Down Expand Up @@ -366,7 +366,7 @@ def program(implicit I : Interacts[CatsApp], D : DataSource[CatsApp]): Free[Cats
}
```

Finally we write one interpreter per ADT and combine them with a `NaturalTransformation` to `Coproduct` so they can be
Finally we write one interpreter per ADT and combine them with a `FunctionK` to `Coproduct` so they can be
compiled and applied to our `Free` program.

```tut:invisible
Expand Down
4 changes: 2 additions & 2 deletions free/src/main/scala/cats/free/Coyoneda.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cats
package free

import cats.arrow.NaturalTransformation
import cats.arrow.FunctionK

/**
* The dual view of the Yoneda lemma. Also a free functor on `F`.
Expand Down Expand Up @@ -38,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: NaturalTransformation[F,G]): Aux[G, A, Pivot] =
final def transform[G[_]](f: FunctionK[F,G]): Aux[G, A, Pivot] =
apply(f(fi))(k)

}
Expand Down
10 changes: 5 additions & 5 deletions free/src/main/scala/cats/free/Free.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ package free
import scala.annotation.tailrec

import cats.data.Xor, Xor.{Left, Right}
import cats.arrow.NaturalTransformation
import cats.arrow.FunctionK

object Free {
/**
Expand Down Expand Up @@ -135,7 +135,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: NaturalTransformation[S,M])(implicit M: Monad[M]): M[A] =
final def foldMap[M[_]](f: FunctionK[S,M])(implicit M: Monad[M]): M[A] =
step match {
case Pure(a) => M.pure(a)
case Suspend(s) => f(s)
Expand All @@ -147,13 +147,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: NaturalTransformation[S,T]): Free[T, A] =
final def mapSuspension[T[_]](f: FunctionK[S,T]): Free[T, A] =
foldMap[Free[T, ?]] {
new NaturalTransformation[S, Free[T, ?]] {
new FunctionK[S, Free[T, ?]] {
def apply[B](fa: S[B]): Free[T, B] = Suspend(f(fa))
}
}(Free.freeMonad)

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

}
16 changes: 8 additions & 8 deletions free/src/main/scala/cats/free/FreeApplicative.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cats
package free

import cats.arrow.NaturalTransformation
import cats.arrow.FunctionK
import cats.data.Const

/** Applicative Functor for Free */
Expand All @@ -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: NaturalTransformation[F,G])(implicit G: Applicative[G]): G[A] =
final def foldMap[G[_]](f: FunctionK[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 @@ -37,26 +37,26 @@ sealed abstract class FreeApplicative[F[_], A] extends Product with Serializable
* Tail recursive only if `F` provides tail recursive interpretation.
*/
final def fold(implicit F: Applicative[F]): F[A] =
foldMap(NaturalTransformation.id[F])
foldMap(FunctionK.id[F])

/** Interpret this algebra into another FreeApplicative */
final def compile[G[_]](f: NaturalTransformation[F,G]): FA[G, A] =
final def compile[G[_]](f: FunctionK[F,G]): FA[G, A] =
foldMap[FA[G, ?]] {
new NaturalTransformation[F, FA[G, ?]] {
new FunctionK[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: NaturalTransformation[F,λ[α => M]]): M =
foldMap[Const[M, ?]](new (NaturalTransformation[F,Const[M, ?]]) {
final def analyze[M:Monoid](f: FunctionK[F,λ[α => M]]): M =
foldMap[Const[M, ?]](new (FunctionK[F,Const[M, ?]]) {
def apply[X](x: F[X]): Const[M,X] = Const(f(x))
}).getConst

/** Compile this FreeApplicative algebra into a Free algebra. */
final def monad: Free[F, A] =
foldMap[Free[F, ?]] {
new NaturalTransformation[F, Free[F, ?]] {
new FunctionK[F, Free[F, ?]] {
def apply[B](fa: F[B]): Free[F, B] = Free.liftF(fa)
}
}
Expand Down
4 changes: 2 additions & 2 deletions free/src/test/scala/cats/free/CoyonedaTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package cats
package free

import cats.tests.CatsSuite
import cats.arrow.NaturalTransformation
import cats.arrow.FunctionK
import cats.laws.discipline.{FunctorTests, SerializableTests}

import org.scalacheck.Arbitrary
Expand All @@ -27,7 +27,7 @@ class CoyonedaTests extends CatsSuite {

test("transform and run is same as applying natural trans") {
val nt =
new NaturalTransformation[Option, List] {
new FunctionK[Option, List] {
def apply[A](fa: Option[A]): List[A] = fa.toList
}
val o = Option("hello")
Expand Down
14 changes: 7 additions & 7 deletions free/src/test/scala/cats/free/FreeApplicativeTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package cats
package free

import cats.tests.CatsSuite
import cats.arrow.NaturalTransformation
import cats.arrow.FunctionK
import cats.laws.discipline.{CartesianTests, ApplicativeTests, SerializableTests}
import cats.data.State

Expand All @@ -18,7 +18,7 @@ class FreeApplicativeTests extends CatsSuite {
implicit def freeApplicativeEq[S[_]: Applicative, A](implicit SA: Eq[S[A]]): Eq[FreeApplicative[S, A]] =
new Eq[FreeApplicative[S, A]] {
def eqv(a: FreeApplicative[S, A], b: FreeApplicative[S, A]): Boolean = {
val nt = NaturalTransformation.id[S]
val nt = FunctionK.id[S]
SA.eqv(a.foldMap(nt), b.foldMap(nt))
}
}
Expand All @@ -44,7 +44,7 @@ class FreeApplicativeTests extends CatsSuite {
val x = FreeApplicative.lift[Id, Int](1)
val y = FreeApplicative.pure[Id, Int](2)
val f = x.map(i => (j: Int) => i + j)
val nt = NaturalTransformation.id[Id]
val nt = FunctionK.id[Id]
val r1 = y.ap(f)
val r2 = r1.compile(nt)
r1.foldMap(nt) should === (r2.foldMap(nt))
Expand All @@ -57,7 +57,7 @@ class FreeApplicativeTests extends CatsSuite {
val r1 = y.ap(f)
val r2 = r1.monad
val nt =
new NaturalTransformation[Id, Id] {
new FunctionK[Id, Id] {
def apply[A](fa: Id[A]): Id[A] = fa
}
r1.foldMap(nt) should === (r2.foldMap(nt))
Expand All @@ -75,7 +75,7 @@ class FreeApplicativeTests extends CatsSuite {

test("FreeApplicative#analyze") {
type G[A] = List[Int]
val countingNT = new NaturalTransformation[List, G] {
val countingNT = new FunctionK[List, G] {
def apply[A](la: List[A]): G[A] = List(la.length)
}

Expand All @@ -97,7 +97,7 @@ class FreeApplicativeTests extends CatsSuite {

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

val f: NaturalTransformation[Foo,Tracked] = new NaturalTransformation[Foo,Tracked] {
val f: FunctionK[Foo,Tracked] = new FunctionK[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: NaturalTransformation[Id,λ[α => String]] = new NaturalTransformation[Id,λ[α => String]] {
val asString: FunctionK[Id,λ[α => String]] = new FunctionK[Id,λ[α => String]] {
def apply[A](a: A): String = a.toString
}

Expand Down
Loading

0 comments on commit 92269f7

Please sign in to comment.