diff --git a/src/main/kotlin/me/alex_s168/kotlin_bits/Clazz.kt b/src/main/kotlin/me/alex_s168/kotlin_bits/Clazz.kt index a6f0ff4..608faad 100644 --- a/src/main/kotlin/me/alex_s168/kotlin_bits/Clazz.kt +++ b/src/main/kotlin/me/alex_s168/kotlin_bits/Clazz.kt @@ -12,8 +12,66 @@ interface IndexableSequence: Sequence { data class Obj(val v: T) +fun Obj?.map(transform: (I) -> O): Obj? = + this?.v?.let { Obj(transform(it)) } + +fun Obj.map(transform: (I) -> O): Obj = + Obj(transform(v)) + data class MutObj(var v: T) +typealias Provider = () -> T + +class Either private constructor( + private val a: Obj?, + private val b: Obj? +) { + fun getAOrNull(): A? = + a?.v + + fun getA(): A = + (a ?: throw Exception("Value of Either is not of type A!")).v + + fun getAOr(prov: Provider): A = + getAOrNull() ?: prov() + + fun getBOrNull(): B? = + b?.v + + fun getB(): B = + (b ?: throw Exception("Value of Either is not of type B!")).v + + fun getBOr(prov: Provider): B = + getBOrNull() ?: prov() + + val isA: Boolean = + a != null + + val isB: Boolean = + b != null + + fun then(af: (A) -> R, bf: (B) -> R): R = + if (isA) af(a!!.v) else bf(b!!.v) + + fun mapA(transform: (A) -> RA): Either = + Either(a.map(transform), b) + + fun mapB(transform: (B) -> RB): Either = + Either(a, b.map(transform)) + + override fun toString(): String = + if (isA) "Either($a)" + else "Either($b)" + + companion object { + fun ofA(a: A): Either = + Either(Obj(a), null) + + fun ofB(b: B): Either = + Either(null, Obj(b)) + } +} + fun lazySequence(vararg init: Pair, default: Obj?, f: (Int, (Int) -> T) -> T): IndexableSequence = object : IndexableSequence { val map = mutableMapOf(*init) @@ -128,7 +186,7 @@ fun Sequence.asIndexable(): IndexableSequence = typealias Operator = (I) -> O -fun caching(tiedGet: () -> T, calc: (T) -> O) = object : Lazy { +fun caching(tiedGet: Provider, calc: (T) -> O) = object : Lazy { private var lastTiedV = tiedGet() private var lastV: O? = null @@ -148,7 +206,7 @@ fun caching(tiedGet: () -> T, calc: (T) -> O) = object : Lazy { lastTiedV == tiedGet() && lastV != null } -fun selfInitializingSequence(block: () -> Sequence): Sequence = +fun selfInitializingSequence(block: Provider>): Sequence = object : Sequence { val seq by lazy(block) @@ -504,7 +562,7 @@ fun unit(v: O): Monad = Monad { v } fun unit(): Monad = - Monad { Unit } + Monad { } fun Monad.bind(op: (I) -> O): Monad = Monad { op(this@bind.impure()) } @@ -524,7 +582,7 @@ fun ByteBatchSequence.stringify(batch: Int = 64): Sequence { } } -fun (() -> RawSource).readerSequence(): ByteBatchSequence = +fun Provider.readerSequence(): ByteBatchSequence = object : ByteBatchSequence { inner class Iter: ByteBatchIterator { val buffered = this@readerSequence().buffered() @@ -595,6 +653,19 @@ fun Monad>>.combine(): Monad = fun Monad>>.combineIter(): Monad = Monad { this@combineIter.impure().forEach { it.impure() } } +fun Monad>.reduce(operation: (acc: S, T) -> S): Monad = + bind { it.reduce(operation) } + +fun Monad>.reduceIter(operation: (acc: S, T) -> S): Monad = + bind { it.reduce(operation) } + +fun Monad>.reduce(each: (T) -> Unit): Monad = + Monad { this@reduce.impure().forEach { each(it) } } + + +fun Monad>.reduceIter(each: (T) -> Unit): Monad = + Monad { this@reduceIter.impure().forEach { each(it) } } + fun Monad>.mapIter(transform: (T) -> R): Monad> = bind { it.map { x -> transform(x) } } @@ -613,6 +684,51 @@ fun Monad.read() = fun readIn() = Monad { generateSequence { readln() } } +fun interface DeferScope { + fun defer(block: () -> Unit) +} + +interface ExecutionScope: DeferScope { + fun onError(block: () -> Unit) + + fun error() + + companion object { + fun create( + defer: (block: () -> Unit) -> Unit, + onError: (block: () -> Unit) -> Unit, + error: () -> Unit, + ) = object : ExecutionScope { + override fun defer(block: () -> Unit) = + defer(block) + + override fun onError(block: () -> Unit) = + onError(block) + + override fun error() = + error() + } + } +} + +fun resourceScoped(block: ExecutionScope.() -> R): R { + val defer = mutableListOf<() -> Unit>() + val onError = mutableListOf<() -> Unit>() + val scope = ExecutionScope.create(defer::add, onError::add) { + throw Exception("Manual error triggered") + } + val ex: Exception + try { + return block(scope) + } catch (e: Exception) { + ex = e + onError.forEach { it.invoke() } + } finally { + defer.forEach { it.invoke() } + } + throw ex +} + /* fun main() { val chain = chain() diff --git a/src/main/kotlin/me/alex_s168/kotlin_bits/Fnp.kt b/src/main/kotlin/me/alex_s168/kotlin_bits/Fnp.kt index a025641..648834b 100644 --- a/src/main/kotlin/me/alex_s168/kotlin_bits/Fnp.kt +++ b/src/main/kotlin/me/alex_s168/kotlin_bits/Fnp.kt @@ -25,5 +25,4 @@ fun pureCat(args: Array): Monad = } .rewrap() .flatten() - .map { unit(it).print() } - .combine() \ No newline at end of file + .reduce { s -> print(s) } \ No newline at end of file