Last active
October 13, 2017 16:12
-
-
Save Mortimerp9/5380105 to your computer and use it in GitHub Desktop.
Sample code for the following post https://coderwall.com/p/pdrz7q
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
object test { | |
/** | |
* The companion object | |
*/ | |
object Reader { | |
/** | |
* automatically wrap a function in a reader | |
*/ | |
implicit def reader[From, To](block: From => To) = Reader[From, To](block) | |
/** | |
* create a reader that does not really depend on anything. This is a way of wrapping an already computed result (like a failure) within a Reader when we need such a return type. | |
*/ | |
def pure[From, To](a: To) = Reader((c: From) => a) | |
/** | |
* resolve a reader | |
*/ | |
def withDependency[F, T](dep: F)(reader: Reader[F, T]): T = reader(dep) | |
} | |
/** | |
* The reader Monad | |
*/ | |
case class Reader[-From, +To](wrappedF: From => To) { | |
def apply(c: From) = wrappedF(c) | |
def map[ToB](transformF: To => ToB): Reader[From, ToB] = | |
Reader(c => transformF(wrappedF(c))) | |
def flatMap[FromB <: From, ToB](f: To => Reader[FromB, ToB]): Reader[FromB, ToB] = | |
Reader(c => f(wrappedF(c))(c)) | |
} | |
//Model | |
case class User(val id: Long) | |
case class Post(val title: String) | |
//Connections | |
trait UserConnection { | |
def readUser(id: Long): Option[User] = Some(User(id)) | |
} | |
trait PostConnection { | |
def readPosts(user: User): Seq[Post] = Seq(Post("test"), Post("test2")) | |
} | |
import Reader._ | |
//a concrete connection | |
type UserPostConn = UserConnection with PostConnection | |
class RealConn extends UserConnection with PostConnection {} | |
val conn = new RealConn | |
/** | |
* all the posts from a user please | |
*/ | |
def userPosts(userID: Long): Reader[UserPostConn, Seq[Post]] = reader { conn => | |
(conn.readUser(userID) map { user => | |
conn.readPosts(user) | |
}) getOrElse (List()) //getting rid of the Option just to simplify the code in this article | |
} | |
/** | |
* just the titles, thank you | |
*/ | |
def titles(id: Long) = userPosts(id).map { postIterable => | |
postIterable.map(_.title) | |
} | |
/** | |
* unwrap the reader given a concrete dependency | |
*/ | |
withDependency(conn) { titles(10l) } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment