Last active
September 15, 2020 16:16
-
-
Save NanoMichael/1639a06805d93319c673b991e13c6047 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
package io.nano | |
import java.util.concurrent.Executor | |
import java.util.concurrent.ExecutorService | |
import java.util.concurrent.Executors | |
import kotlin.concurrent.thread | |
fun main() { | |
testFmap() | |
println() | |
testBind() | |
Thread.sleep(1000 * 5) | |
println() | |
testZip() | |
Thread.sleep(1000 * 5) | |
println() | |
testRunOn() | |
executor.shutdown() | |
Thread.sleep(1000 * 5) | |
println() | |
testList() | |
} | |
fun testBind() { | |
val f = id("./file/path") | |
.bind { path -> | |
println("run in: ${Thread.currentThread()}, $path") | |
::readFileCallback.currying()(path) | |
} | |
.bind { url -> | |
println("run in: ${Thread.currentThread()}, $url") | |
::readNetCallback.currying()(url) | |
} | |
.bind { content -> | |
println("run in: ${Thread.currentThread()}, $content") | |
::saveIntoFileCallback.currying()(content) | |
} | |
f { println("run in: ${Thread.currentThread()}, $it") } | |
} | |
fun testFmap() { | |
val f = id("./file/path") | |
.fmap { path -> | |
println(path) | |
readFile(path) | |
} | |
.fmap { url -> | |
println(url) | |
readNet(url) | |
} | |
.fmap { content -> | |
println(content) | |
saveIntoFile(content) | |
} | |
id("./file/path") fmap ::readFile fmap ::readNet fmap ::saveIntoFile | |
f { println(it) } | |
} | |
fun testZip() { | |
val f = id("./file/path") | |
.bind { path -> | |
println("run in: ${Thread.currentThread()}, $path") | |
::readFileCallback.currying()(path) | |
} | |
.doAction { println("action: $it") } | |
.zip(id("content")) { url, content -> | |
println("run in: ${Thread.currentThread()}, $url, $content") | |
url to content | |
} | |
f { println("run in: ${Thread.currentThread()}, $it") } | |
} | |
fun testRunOn() { | |
val f = id("./file/path") | |
.fmap { path -> | |
println(path) | |
readFile(path) | |
} | |
.fmap { url -> | |
println(url) | |
readNet(url) | |
} | |
.fmap { content -> | |
println(content) | |
saveIntoFile(content) | |
} | |
.runOn(executor) | |
.fmap { | |
println("toUpperCase, run in ${Thread.currentThread()}, $it") | |
it.toUpperCase() | |
} | |
f { println("run in: ${Thread.currentThread()}, $it") } | |
} | |
fun testList() { | |
val f = list("file1", "file2", "file3") | |
.doAction { | |
println("file: $it") | |
} | |
.bind { | |
::readFileCallback.currying()(it) | |
} | |
.doAction { | |
println("url: $it") | |
} | |
.bind { | |
::readNetCallback.currying()(it) | |
} | |
.doAction { | |
println("content: $it") | |
} | |
.bind { | |
::saveIntoFileCallback.currying()(it) | |
} | |
.doAction { | |
println("save file path: $it") | |
} | |
f { println(it) } | |
} | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
// in function style | |
fun <T1, T2, R> ((T1, T2) -> R).currying() = { t1: T1 -> | |
{ t2: T2 -> this(t1, t2) } | |
} | |
typealias Callback<T> = (T) -> Unit | |
typealias F<T> = (Callback<T>) -> Unit | |
fun <T> id(x: T): F<T> = { f -> f(x) } | |
fun <T> list(vararg xs: T): F<T> = { f -> xs.forEach(f) } | |
infix fun <T, R> F<T>.fmap(f: (T) -> R): F<R> = { callback: Callback<R> -> | |
this { t -> callback(f(t)) } | |
} | |
infix fun <T, R> F<T>.bind(f: (T) -> F<R>): F<R> = { callback: Callback<R> -> | |
this { t -> f(t)(callback) } | |
} | |
fun <T1, T2, R> F<T1>.zip(other: F<T2>, f: (T1, T2) -> R): F<R> = { callback: Callback<R> -> | |
val results = arrayOfNulls<Any>(2) | |
val run = { | |
if (results[0] != null && results[1] != null) { | |
callback(f(results[0] as T1, results[1] as T2)) | |
} | |
} | |
this.fmap { t1 -> results[0] = t1 }() { run() } | |
other.fmap { t2 -> results[1] = t2 }() { run() } | |
} | |
fun <T> F<T>.doAction(f: (T) -> Unit): F<T> = { callback: Callback<T> -> | |
this.fmap { t -> f(t); t }() { t -> callback(t) } | |
} | |
fun <T> F<T>.runOn(executor: Executor) = { callback: Callback<T> -> | |
this { t -> executor.execute { callback(t) } } | |
} | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
// in objective style | |
interface Fun<T> { | |
operator fun invoke(callback: (T) -> Unit) | |
} | |
class Id<T>(val t: T) : Fun<T> { | |
override fun invoke(callback: (T) -> Unit) { | |
callback(t) | |
} | |
} | |
infix fun <T, R> Fun<T>.fmap(f: (T) -> R): Fun<R> = object : Fun<R> { | |
override fun invoke(callback: (R) -> Unit) { | |
this@fmap { t -> callback(f(t)) } | |
} | |
} | |
infix fun <T, R> Fun<T>.bind(f: (T) -> Fun<R>): Fun<R> = object : Fun<R> { | |
override fun invoke(callback: (R) -> Unit) { | |
this@bind { t -> f(t)(callback) } | |
} | |
} | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
fun readFile(path: String) = "https://github.com/nanomichael/$path" | |
fun readNet(url: String) = "content from $url" | |
fun saveIntoFile(content: String) = "./content/path/'$content'" | |
val executor: ExecutorService = Executors.newCachedThreadPool() | |
fun readFileCallback(path: String, callback: Callback<String>) { | |
thread(name = "thread-read-file") { | |
Thread.sleep(1000) | |
callback(readFile(path)) | |
} | |
} | |
fun readNetCallback(url: String, callback: Callback<String>) { | |
thread(name = "thread-read-net") { | |
Thread.sleep(1000) | |
callback(readNet(url)) | |
} | |
} | |
fun saveIntoFileCallback(content: String, callback: Callback<String>) { | |
thread(name = "thread-save-file") { | |
Thread.sleep(1000) | |
callback(saveIntoFile(content)) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment