Skip to content

Instantly share code, notes, and snippets.

@wemrysi
Forked from tonymorris/RefactoringPuzzle.scala
Last active December 17, 2015 23:18
Show Gist options
  • Save wemrysi/5688105 to your computer and use it in GitHub Desktop.
Save wemrysi/5688105 to your computer and use it in GitHub Desktop.
object RefactorPuzzle {
case class IntRdr[+A](read: Int => A) {
def map[B](f: A => B): IntRdr[B] =
IntRdr(f compose read)
def flatMap[B](f: A => IntRdr[B]): IntRdr[B] =
IntRdr(n => f(read(n)).read(n))
}
object IntRdr {
def apply[A](a: A): IntRdr[A] =
IntRdr(_ => a)
}
// Return all the Some values, or None if not all are Some.
def runOptions[A](x: List[Option[A]]): Option[List[A]] =
x.foldRight[Option[List[A]]](Option(Nil))((a, b) => a.flatMap(aa => b.map(aa :: _)))
// Apply an Int to a list of int readers and return the list of return values.
def runIntRdrs[A](x: List[IntRdr[A]]): IntRdr[List[A]] =
x.foldRight[IntRdr[List[A]]](IntRdr(Nil))((a, b) => a.flatMap(aa => b.map(aa :: _)))
/*
========================
THE REFACTORING PUZZLE
========================
The two functions `runOptions` and `runIntRdrs` share a lot of duplicated code.
This is demonstrated below.
How to refactor this code to remove the code duplication?
*/
//------- ------------- ------- -----------
//def runOptions[A](x: List[Option[A]]): Option[List[A]] =
//def runIntRdrs[A](x: List[IntRdr[A]]): IntRdr[List[A]] =
// ------------ ----------- -------------------------------------------------
// x.foldRight[Option[List[A]]](Option(Nil))((a, b) => a.flatMap(aa => b.map(aa :: _)))
// x.foldRight[IntRdr[List[A]]](IntRdr(Nil))((a, b) => a.flatMap(aa => b.map(aa :: _)))
import scalaz.{Applicative, Monad}
import scalaz.syntax.traverse._
import scalaz.std.list._
import scalaz.std.option._
implicit def intRdrMonad: Monad[IntRdr] = new Monad[IntRdr]
def point[A](a: => A): IntRdr[A] = IntRdr(a)
def bind[A, B](fa: IntRdr[A])(f: A => IntRdr[B]): IntRdr[B] = fa flatMap f
}
def runList[F[_]: Applicative, A](x: List[F[A]]): F[List[A]] = x.sequence
def runOptions[A](x: List[Option[A]]) = runList(x)
def runIntRdrs[A](x: List[IntRdr[A]]) = runList(x)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment