Skip to content

Instantly share code, notes, and snippets.

@folone
Forked from tonymorris/TReader.scala
Created October 15, 2012 10:57
Show Gist options
  • Save folone/3891933 to your computer and use it in GitHub Desktop.
Save folone/3891933 to your computer and use it in GitHub Desktop.
Reader monad in Scala
case class T() // your data type that you want to "implicitly" thread through
case class TReader[+A](run: T ⇒ A) {
def map[B](f: A ⇒ B): TReader[B] =
TReader((r: T) ⇒ f(run(r)))
def flatMap[B](f: A ⇒ TReader[B]): TReader[B] =
TReader((r: T) ⇒ f(run(r)).run(r))
def &&&[B](x: TReader[B]): TReader[(A, B)] =
for {
a ← this
b ← x
} yield (a, b)
}
object TReader {
def point[A](a: A): TReader[A] = TReader(_ ⇒ a)
def sequence[A](t: List[TReader[A]]): TReader[List[A]] =
t.foldLeft(point(Nil: List[A])) { (acc, v) ⇒
for {
x ← v
xs ← acc
} yield x::xs
}
// Same type as filter, but TReader wraps every type in return position.
// So we "thread through" our T value, while filtering a list.
def filter[A](p: A ⇒ TReader[Boolean], a: List[A]): TReader[List[A]] =
a match {
case x::xs ⇒ for {
flg ← p(x)
ys ← filter(p, xs)
} yield if(flg) x::ys else ys
case Nil ⇒ point(Nil)
}
def fill[A](n: Int)(t: TReader[A]): TReader[List[A]] =
t.map(a ⇒ List.fill(n)(a))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment