Skip to content

Instantly share code, notes, and snippets.

@NanoMichael
Last active September 15, 2020 16:16
Show Gist options
  • Save NanoMichael/1639a06805d93319c673b991e13c6047 to your computer and use it in GitHub Desktop.
Save NanoMichael/1639a06805d93319c673b991e13c6047 to your computer and use it in GitHub Desktop.
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