Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/main/scala/learnfp/applicative/Reader.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package learnfp.applicative

import learnfp.functor.Reader
import learnfp.functor.ReaderInstance._

object ReaderInstance {
implicit def readerApplicativeInstance[R] = new Applicative[({type E[X] = Reader[R, X]})#E] {
override def pure[A](a: A): Reader[R,A] = Reader(_ => a)

override def <*>[A, B](fx: Reader[R,A => B])(a: Reader[R,A]): Reader[R,B] = Reader(r => fx.read(r)(a.read(r)))
}

implicit def readerToApplicativeOps[R, A, B](fx: Reader[R, A => B]) =
new FxApplicativeOps[A, B, ({type E[X] = Reader[R, X]})#E](fx)

class ReaderPureOps[A](a: A) {
def pure[R]: Reader[R, A] = readerApplicativeInstance[R].pure(a)
}
implicit def toPureOps[A](a: A) = new ReaderPureOps[A](a)
}
12 changes: 12 additions & 0 deletions src/main/scala/learnfp/free/Free.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import learnfp.monad.{Monad, MonadOps}
import learnfp.functor.{Functor, FunctorOps}

import scala.annotation.tailrec
import learnfp.applicative.Applicative
import learnfp.applicative.FxApplicativeOps

sealed trait Free[F[_], A]
final case class Return[F[_], A](a:A) extends Free[F, A]
Expand All @@ -28,6 +30,16 @@ object Free {

implicit def freeToMonadOps[F[_], A](a:Free[F, A]) = new MonadOps[A, ({type E[X] = Free[F, X]})#E](a)

implicit def freeApplicativeInstance[F[_]] = new Applicative[({type E[X] = Free[F, X]})#E] {
override def pure[A](a: A): Free[F,A] = Return(a)

override def <*>[A, R](fx: Free[F,A => R])(a: Free[F,A]): Free[F,R] =
FlatMap(fx, (f: A => R) => FlatMap(a, (innerA: A) => Return(f(innerA))))
}

implicit def freeToFxApplicativeOps[F[_], A, R](a: Free[F, A => R])(implicit applicative: Applicative[F]): FxApplicativeOps[A, R, ({type E[X] = Free[F, X]})#E] =
new FxApplicativeOps[A, R, ({type E[X] = Free[F, X]})#E](a)

def liftF[F[_], A](a:F[A]):Free[F, A] = LiftF[F, A](a)

def foldF[F[_], M[_], A](a:Free[F, A])(trans:Natural[F, M])(implicit f:Functor[M], m:Monad[M]):M[A] = a match {
Expand Down
21 changes: 21 additions & 0 deletions src/main/scala/learnfp/functor/Reader.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package learnfp.functor

case class Reader[R, A](read: R => A)

object Reader {
def ask[R]: Reader[R, R] = Reader(r => r)
}

object ReaderInstance {
implicit def readerInstance[R] = new Functor[({type E[X] = Reader[R, X]})#E] {
override def fmap[A, B](a: Reader[R, A])(fx: A => B): Reader[R, B] = Reader(r => fx(a.read(r)))
}

implicit def readerToFunctorOps[A, R](a: Reader[R, A]) = new FunctorOps[A, ({type E[X] = Reader[R, X]})#E](a)

class ReaderFunctorOps[A, B](fx:A => B) {
def `<$>`[R](a: Reader[R, A]): Reader[R, B] = a fmap fx
}

implicit def readerToFunctorFxOps[A, R](fx: A => R) = new ReaderFunctorOps[A, R](fx)
}
15 changes: 15 additions & 0 deletions src/main/scala/learnfp/monad/Reader.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package learnfp.monad


import learnfp.functor.Reader
import learnfp.functor.ReaderInstance._

object ReaderInstance {
implicit def readerMonadInstance[R] = new Monad[({type E[X] = Reader[R, X]})#E] {
override def pure[A](a: A): Reader[R,A] = Reader(_ => a)

override def flatMap[A, B](a: Reader[R,A])(fx: A => Reader[R,B]): Reader[R,B] = Reader(r => fx(a.read(r)).read(r))
}

implicit def readerToMonadOps[R, A](r: Reader[R, A]) = new MonadOps[A, ({type E[X] = Reader[R, X]})#E](r)
}
18 changes: 18 additions & 0 deletions src/main/scala/learnfp/transformer/IdT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package learnfp.transformer

import learnfp.functor.{Functor, FunctorOps, Id}
import learnfp.monad.{Monad, MonadOps, MonadOpsPure}
import learnfp.applicative.FxApplicativeOps
import learnfp.applicative.Applicative

case class IdT[A, F[_]](runIdT:F[Id[A]])

Expand All @@ -22,6 +24,22 @@ object IdT {
implicit def idtToMonadOps[A, M[_]](a:IdT[A, M])(implicit m:Monad[M], f:Functor[M]) =
new MonadOps[A, ({type E[X] = IdT[X, M]})#E](a)

implicit def idtApplicativeInstance[M[_]](implicit outerApplicative: Applicative[M], outerFunctor: Functor[M]) = new Applicative[({type E[X] = IdT[X, M]})#E] {
override def pure[A](a: A): IdT[A,M] = IdT(outerApplicative.pure(Id(a)))

override def <*>[A, R](fx: IdT[A => R,M])(a: IdT[A,M]): IdT[R,M] = IdT({
// lift operation into container with inner Id
val lifted: M[Id[A] => Id[R]] = outerFunctor.fmap(fx.runIdT)(idAToR => (idA: Id[A]) => Id(idAToR.value(idA.value)))
// prepare operand of container as Id
val operand: M[Id[A]] = a.runIdT
// apply with outer applicative
outerApplicative.<*>(lifted)(operand)
})
}

implicit def idtToFxApplicativeOps[A, R, F[_]](a: IdT[A => R, F])(implicit applicative: Applicative[F]): FxApplicativeOps[A, R, ({type E[X] = IdT[X, F]})#E] =
new FxApplicativeOps[A, R, ({type E[X] = IdT[X, F]})#E](a)

implicit def idtMonadTransInstance[M[_]](implicit m:Monad[M], f:Functor[M]) = new MonadTransformer[M, IdT] {
override def lift[A](a: M[A]): IdT[A, M] = IdT(f.fmap(a){ x:A => Id(x) })
}
Expand Down
21 changes: 21 additions & 0 deletions src/main/scala/learnfp/transformer/MaybeT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import learnfp.functor.Maybe.{Just, Maybe, Nothing}
import learnfp.monad.{Monad, MonadOps}
import learnfp.functor.FunctorOps._
import learnfp.monad.MonadOps._
import learnfp.applicative.FxApplicativeOps
import learnfp.applicative.Applicative

case class MaybeT[A, M[_]](runMaybeT:M[Maybe[A]])(implicit f:Functor[M], m:Monad[M])

Expand Down Expand Up @@ -35,6 +37,25 @@ object MaybeT {
implicit def maybeTToMonadOps[A, M[_]](a:MaybeT[A, M])(implicit m:Monad[M], f:Functor[M]) =
new MonadOps[A, ({type E[X] = MaybeT[X, M]})#E](a)

implicit def maybeTApplicativeInstance[M[_]](implicit f: Functor[M], m: Monad[M], ap: Applicative[M]) = new Applicative[({type E[X] = MaybeT[X, M]})#E] {
override def pure[A](a: A): MaybeT[A,M] = MaybeT(ap.pure(Just[A](a)))

override def <*>[A, R](fx: MaybeT[A => R,M])(a: MaybeT[A,M]): MaybeT[R,M] = MaybeT({
// lift operation into container with inner Maybe
val lifted: M[Maybe[A] => Maybe[R]] = f.fmap(fx.runMaybeT)(maybeAToR => maybeA => (maybeAToR, maybeA) match {
case (Just(aToR), Just(innerA)) => Just(aToR(innerA))
case _ => Nothing()
})
// prepare operand of container as Maybe
val operand: M[Maybe[A]] = a.runMaybeT
// apply with outer applicative
ap.<*>(lifted)(operand)
})
}

implicit def maybeTToFxApplicativeOps[A, R, F[_]](a: MaybeT[A => R, F])(implicit applicative: Applicative[F]): FxApplicativeOps[A, R, ({type E[X] = MaybeT[X, F]})#E] =
new FxApplicativeOps[A, R, ({type E[X] = MaybeT[X, F]})#E](a)

implicit def maybeTMonadTransInstance[M[_]](implicit f:Functor[M], m:Monad[M]) = new MonadTransformer[M, MaybeT] {
override def lift[A](a: M[A]): MaybeT[A, M] = MaybeT { f.fmap(a) { av => Just(av)} }
}
Expand Down
60 changes: 60 additions & 0 deletions src/main/scala/learnfp/transformer/ReaderT.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package learnfp.transformer


import learnfp.functor.{Functor, FunctorOps}
import learnfp.functor.FunctorOps._
import learnfp.monad.{Monad, MonadOps}
import learnfp.monad.MonadOps._
import learnfp.applicative.Applicative
import learnfp.applicative.FxApplicativeOps

case class ReaderT[A, M[_], R](runReaderT:R => M[A])(implicit f:Functor[M], m:Monad[M])

object ReaderT {
implicit def readerTFuctorInstance[R, M[_]](implicit f:Functor[M], m:Monad[M]) =
new Functor[({type E[X] = ReaderT[X, M, R]})#E] {
override def fmap[A, B](a: ReaderT[A,M,R])(fx: A => B): ReaderT[B,M,R] = ReaderT(r => f.fmap(a.runReaderT(r))(fx))
}

implicit def toFunctorOps[A, M[_], R](a: ReaderT[A, M, R])(implicit f:Functor[M], m:Monad[M]): FunctorOps[A, ({type E[X] = ReaderT[X, M, R]})#E] =
new FunctorOps[A, ({type E[X] = ReaderT[X, M, R]})#E](a)

implicit def readerTMonadInstance[R, M[_]](implicit f:Functor[M], m:Monad[M]) =
new Monad[({type E[X] = ReaderT[X, M, R]})#E]() {
override def pure[A](a: A): ReaderT[A, M, R] = ReaderT(_ => m.pure(a))
override def flatMap[A, B](a: ReaderT[A, M, R])(fx: A => ReaderT[B, M, R]): ReaderT[B, M, R] =
ReaderT(r => m.flatMap(a.runReaderT(r))(innerA => fx(innerA).runReaderT(r)))
}

def lift[A,M[_], R](am:M[A])(implicit f:Functor[M], m:Monad[M]): ReaderT[A, M, R] = ReaderT(_ => am)

implicit def readerTToMonadOps[A, M[_], R](a:ReaderT[A, M, R])(implicit f:Functor[M], m:Monad[M]) =
new MonadOps[A, ({type E[X] = ReaderT[X, M, R]})#E](a)

implicit def readerTApplicativeInstance[R, M[_]](implicit f:Functor[M], m:Monad[M], ap:Applicative[M]) =
new Applicative[({type E[X] = ReaderT[X, M, R]})#E]() {
override def pure[A](a: A): ReaderT[A,M,R] = ReaderT(_ => m.pure(a))

override def <*>[A, B](fx: ReaderT[A => B,M,R])(a: ReaderT[A,M,R]): ReaderT[B,M,R] = ReaderT({r =>
// lift operation into container with inner Reader
val lifted: M[A => B] = fx.runReaderT(r)
// prepare operand of container as Reader
val operand: M[A] = a.runReaderT(r)
// apply with outer applicative
ap.<*>(lifted)(operand)
})
}

implicit def readerTToFxApplicativeOps[A, RR, M[_], R](a: ReaderT[A => RR, M, R])(implicit applicative: Applicative[M]): FxApplicativeOps[A, RR, ({type E[X] = ReaderT[X, M, R]})#E] =
new FxApplicativeOps[A, RR, ({type E[X] = ReaderT[X, M, R]})#E](a)


def pure[A, M[_], R](a:A)(implicit f:Functor[M], m:Monad[M]) = readerTMonadInstance[R, M].pure(a)

implicit def readerTMonadTransInstance[A, M[_], R](implicit f:Functor[M], m:Monad[M]) =
new MonadTransformer[M, ({type E[X, Y[_]] = ReaderT[X, Y, R]})#E] {
override def lift[A](a: M[A]): ReaderT[A, M, R] = ReaderT.lift(a)
}

def ask[M[_], R](implicit f:Functor[M], m:Monad[M]): ReaderT[R, M, R] = ReaderT(m.pure(_))
}
21 changes: 21 additions & 0 deletions src/main/scala/learnfp/transformer/StateT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import learnfp.functor.StateInstance._
import learnfp.monad.{Monad, MonadOps}
import learnfp.monad.MonadOps._
import learnfp.monad.StateInstance._
import learnfp.applicative.Applicative
import learnfp.applicative.FxApplicativeOps

case class StateT[S, M[_], A](runStateT: S => M[(S, A)])(implicit m:Monad[M])

Expand All @@ -31,6 +33,25 @@ object StateT {
implicit def stateTToMonadOps[S, M[_], A](a:StateT[S, M, A])(implicit f:Functor[M], m:Monad[M]) =
new MonadOps[A, ({type E[X] = StateT[S, M, X]})#E](a)

implicit def stateTApplicativeInstance[S, M[_]](implicit f:Functor[M], m:Monad[M], ap: Applicative[M]) =
new Applicative[({type E[X] = StateT[S, M, X]})#E]() {
override def pure[A](a: A): StateT[S,M,A] = StateT(m.pure(_, a))

override def <*>[A, R](fx: StateT[S,M,A => R])(a: StateT[S,M,A]): StateT[S,M,R] = StateT { s =>
// lift operation into container with inner State
val lifted: M[A => (S, R)] = f.fmap(fx.runStateT(s)){
case (newState, aToR) => (innerA: A) => (newState, aToR(innerA))
}
// prepare operand of container as State
val operand: M[A] = f.fmap(a.runStateT(s))(_._2)
// apply with outer applicative
ap.<*>(lifted)(operand)
}
}

implicit def idtToFxApplicativeOps[S, M[_], A, R](a: StateT[S, M, A => R])(implicit applicative: Applicative[M]): FxApplicativeOps[A, R, ({type E[X] = StateT[S, M, X]})#E] =
new FxApplicativeOps[A, R, ({type E[X] = StateT[S, M, X]})#E](a)

implicit def stateTMonadTransformerInstance[S, M[_]](implicit f:Functor[M], m:Monad[M]) =
new MonadTransformer[M, ({type E[X, Y[_]] = StateT[S, Y, X]})#E] {
override def lift[A](a: M[A]): StateT[S, M, A] = {
Expand Down
24 changes: 24 additions & 0 deletions src/main/scala/learnfp/transformer/WriterT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import learnfp.monoid.Monoid
import learnfp.monoid.MonoidOps._
import learnfp.functor.WriterInstance._
import learnfp.monad.WriterInstance._
import learnfp.applicative.Applicative
import learnfp.applicative.FxApplicativeOps

case class WriterT[A, M[_], W](runWriterT:() => M[(W, A)])(implicit f:Functor[M], m:Monad[M], w:Monoid[W])

Expand Down Expand Up @@ -49,6 +51,28 @@ object WriterT {
m.pure((w.mzero, a))
}

implicit def writerTApplicativeInstance[W, M[_]](implicit f:Functor[M], m:Monad[M], ap: Applicative[M], w:Monoid[W]) =
new Applicative[({type E[X] = WriterT[X, M, W]})#E]() {
override def pure[A](a: A): WriterT[A,M,W] = WriterT(() => m.pure((w.mzero, a)))

override def <*>[A, R](fx: WriterT[A => R,M,W])(a: WriterT[A,M,W]): WriterT[R,M,W] = WriterT{ () =>
// lift operation into container with inner Writer
val lifted: M[((W, A)) => (W, R)] = f.fmap(fx.runWriterT()){
case (firstW, aToR) => {
case (secondW, innerA) => (w.mappend(firstW, secondW), aToR(innerA))
}
}
// prepare operand of container as Writer
val operand: M[(W, A)] = a.runWriterT()
// apply with outer applicative
ap.<*>(lifted)(operand)
}
}

implicit def writerTToFxApplicativeOps[A, R, M[_], W](a: WriterT[A => R, M, W])(implicit applicative: Applicative[M]): FxApplicativeOps[A, R, ({type E[X] = WriterT[X, M, W]})#E] =
new FxApplicativeOps[A, R, ({type E[X] = WriterT[X, M, W]})#E](a)


implicit def writerTMonadTransInstance[A, M[_], W](implicit f:Functor[M], m:Monad[M], w:Monoid[W]) =
new MonadTransformer[M, ({type E[X, Y[_]] = WriterT[X, Y, W]})#E] {
override def lift[A](a: M[A]): WriterT[A, M, W] = WriterT.lift(a)
Expand Down