Created
April 11, 2012 16:59
-
-
Save tonymorris/2360532 to your computer and use it in GitHub Desktop.
Reader/Writer/State transformer in Scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
case class ReaderWriterStateT[R, W, S, F[_], A]( | |
run: (R, S) => F[(W, A, S)] | |
) { | |
def map[B](f: A => B)(implicit F: Functor[F]) | |
: ReaderWriterStateT[R, W, S, F, B] = | |
ReaderWriterStateT { | |
case (r, s) => F.map(run(r, s)) { | |
case (w, a, s) => (w, f(a), s) | |
} | |
} | |
def flatMap[B](f: A => ReaderWriterStateT[R, W, S, F, B]) | |
(implicit F: FlatMap[F], W: Semigroup[W]) | |
: ReaderWriterStateT[R, W, S, F, B] = | |
ReaderWriterStateT { | |
case (r, s) => F.flatMap(run(r, s)) { | |
case (w1, a, s1) => F.map(f(a) run (r, s1)) { | |
case (w2, b, s2) => (W.op(w1, w2), b, s2) | |
} | |
} | |
} | |
} | |
object ReaderWriterStateT { | |
type ReaderWriterState[R, W, S, A] = | |
ReaderWriterStateT[R, W, S, Id, A] | |
} | |
case class ReaderT[A, F[_], B]( | |
rd: A => F[B] | |
) { | |
def rws[W, S](implicit F: Functor[F], W: Monoid[W]) | |
: ReaderWriterStateT[A, W, S, F, B] = | |
ReaderWriterStateT { | |
case (r, s) => F.map(rd(r))( | |
(W.id, _, s) | |
) | |
} | |
} | |
object ReaderT { | |
type Reader[A, B] = | |
ReaderT[A, Id, B] | |
} | |
case class WriterT[W, F[_], A]( | |
wx: F[(W, A)] | |
) { | |
def rws[R, S](implicit F: Functor[F]) | |
: ReaderWriterStateT[R, W, S, F, A] = | |
ReaderWriterStateT { | |
case (r, s) => F.map(wx){ | |
case (w, a) => (w, a, s) | |
} | |
} | |
} | |
object WriterT { | |
type Writer[W, A] = | |
WriterT[W, Id, A] | |
} | |
case class StateT[S, F[_], A]( | |
st: S => F[(A, S)] | |
) { | |
def rws[W, R](implicit F: Functor[F], W: Monoid[W]) | |
: ReaderWriterStateT[R, W, S, F, A] = | |
ReaderWriterStateT { | |
case (r, s) => F.map(st(s)){ | |
case (a, s) => (W.id, a, s) | |
} | |
} | |
} | |
object StateT { | |
type State[S, A] = | |
StateT[S, Id, A] | |
} | |
case class Id[A](a: A) | |
object Id { | |
implicit val IdFlatMap: FlatMap[Id] = | |
new FlatMap[Id] { | |
def fmap[A, B](f: A => B) = | |
i => Id(f(i.a)) | |
def bind[A, B](f: A => Id[B]) = | |
i => f(i.a) | |
} | |
} | |
trait Functor[F[_]] { | |
def fmap[A, B](f: A => B): F[A] => F[B] | |
def map[A, B](a: F[A])(f: A => B): F[B] = | |
fmap(f)(a) | |
} | |
trait FlatMap[F[_]] extends Functor[F] { | |
def bind[A, B](f: A => F[B]): F[A] => F[B] | |
def flatMap[A, B](a: F[A])(f: A => F[B]): F[B] = | |
bind(f)(a) | |
} | |
trait Semigroup[A] { | |
def op(a1: A, a2: A): A | |
} | |
trait Monoid[A] extends Semigroup[A] { | |
def id: A | |
} |
Thanks for the thought provoking talk. Could you take a look at my attempt to use RWST here: https://gist.github.com/2364137 -- specifically, the definition of the log and the invokeService functions? I had to create PointedFunctor in order to implement log generically. Is that the correct approach?
On 12/04/12 11:45, Michael Pilquist wrote:
Thanks for the thought provoking talk. Could you take a look at my attempt to use RWST here: https://gist.github.com/2364137 -- specifically, the definition of the log and the invokeService functions? I had to create PointedFunctor in order to implement log generically. Is that the correct approach?
---
Reply to this email directly or view it on GitHub:
https://gist.github.com/2360532
Looks pretty spot-on.
Often, the point operation exists alongside an existing trait, so as to
provide laws. e.g. trait Functor; trait PointedFunctor extends Functor.
There is a solid movement for restructuring the position of the point
operation in class hierarchies, of which I am a part of. Here is a
diagram of it: http://hackage.haskell.org/package/semigroupoids (though
I still have more minor reservations here).
##
Tony Morris
http://tmorris.net/
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks Mr Observant!