Created
July 5, 2020 03:37
-
-
Save sjmyuan/2e16726a34b2b6b329954f03284a7afc to your computer and use it in GitHub Desktop.
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 Reader[A, B](run: A => B) { | |
def map[C](f: B => C): Reader[A, C] = { | |
val runN: A => C = (x: A) => f(run(x)) | |
Reader(runN) | |
} | |
def flatMap[C](f: B => Reader[A, C]): Reader[A, C] = { | |
val runN: A => C = (x: A) => f(run(x)).run(x) | |
Reader(runN) | |
} | |
} | |
object Reader { | |
def ask[A]: Reader[A, A] = Reader[A, A](identity) | |
} | |
trait HttpRequest { | |
def get(url: String): String | |
} | |
class LogHttpRequest extends HttpRequest { | |
override def get(url: String): String = { | |
println(s"send request to ${url}") | |
List(1, 2, 3, 4, 5, 6).mkString(",") | |
} | |
} | |
trait Database { | |
def runSql(sql: String): Unit | |
} | |
class LogDatabase extends Database { | |
override def runSql(sql: String): Unit = println(s"run sql ${sql}") | |
} | |
trait DataSource[A] { | |
def getData: Reader[A, List[Int]] | |
} | |
class HttpDataSource extends DataSource[Env] { | |
override def getData: Reader[Env, List[Int]] = | |
for { | |
env <- Reader.ask[Env] | |
data = env.http.get("http://example.com/data").split(",").map(_.toInt).toList | |
} yield data | |
} | |
trait DataStore[A] { | |
def save(data: List[Int]): Reader[A, Unit] | |
} | |
class DatabaseStore extends DataStore[Env] { | |
override def save(data: List[Int]): Reader[Env, Unit] = | |
for { | |
env <- Reader.ask[Env] | |
} yield env.database.runSql( | |
s"insert into data_table values(${data.mkString(",")})" | |
) | |
} | |
trait DataEncoder { | |
def encode(data: List[Int]): List[Int] | |
} | |
class PlusOneEncoder extends DataEncoder { | |
def encode(data: List[Int]): List[Int] = { | |
println(s"encoding ${data}") | |
data.map(_ + 1) | |
} | |
} | |
case class Env(http: HttpRequest, database: Database, source: DataSource[Env], store: DataStore[Env], encoder: DataEncoder) | |
class DataJob { | |
def run: Reader[Env, Unit] = | |
for { | |
env <- Reader.ask[Env] | |
data <- env.source.getData | |
val encodedData = env.encoder.encode(data) | |
_ <- env.store.save(encodedData) | |
} yield () | |
} | |
object Main { | |
def main() { | |
val http = new LogHttpRequest() | |
val database = new LogDatabase() | |
val source = new HttpDataSource | |
val store = new DatabaseStore | |
val encoder = new PlusOneEncoder() | |
val env = Env(http, database, source, store, encoder) | |
val program = new DataJob | |
program.run.run(env) | |
} | |
} | |
Main.main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment