-
-
Save hikaMaeng/42ec68d6fdf53166f38b59f797add699 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
@file:Suppress("NOTHING_TO_INLINE") | |
package kore.wrap | |
/** | |
* 성공, 실패를 내포하는 결과값 보고 객체. 최초 값을 람다로 설정하면 이후 모든 map연산이 지연연산으로 처리됨 | |
*/ | |
object W{ | |
/** 예외 발생이 가능한 블록을 실행하고 그 결과에 따라 Wrap생성 */ | |
inline fun <VALUE:Any>catch(throwableBlock:()->VALUE): Wrap<VALUE> = try { | |
Wrap(throwableBlock()) | |
}catch(e:Throwable){ | |
Wrap(e) | |
} | |
/** 정상인 값을 생성함 */ | |
inline operator fun <VALUE:Any>invoke(value:VALUE): Wrap<VALUE> = Wrap(value) | |
/** 정상인 값을 람다로 생성함. 이후 모든 처리는 지연으로 처리되고 invoke까지 평가가 미뤄짐 */ | |
inline operator fun <VALUE:Any>invoke(block:Thunk<VALUE>): Wrap<VALUE> = Wrap(block) | |
/** 실패인 값을 예외로 생성함. 반드시 타입파라메터를 지정해야 함*/ | |
inline operator fun <VALUE:Any>invoke(value:Throwable): Wrap<VALUE> = Wrap(value) | |
@PublishedApi internal val END = invoke<Nothing>(Throwable("END")) | |
inline fun <VALUE:Any>end():Wrap<VALUE> = END | |
inline fun isEnd(target:Wrap<*>):Boolean = END == target | |
} |
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
@file:Suppress("NOTHING_TO_INLINE", "FunctionName") | |
package kore.wrap | |
import kore.wrap.WList.Cons | |
import kore.wrap.WList.Nil | |
sealed class WList<out ITEM:Any>{ | |
data object Nil: WList<Nothing>() | |
data class Cons<out ITEM:Any> @PublishedApi internal constructor( | |
@PublishedApi internal val head:ITEM, | |
@PublishedApi internal val tail:Wrap<WList<ITEM>> | |
): WList<ITEM>() | |
companion object{ | |
inline operator fun <ITEM:Any> invoke(vararg items:ITEM): WList<ITEM> | |
= items.foldRight(invoke()){ item, acc ->Cons(item, W{acc})} | |
inline operator fun <ITEM:Any> invoke(): WList<ITEM> = Nil | |
} | |
val size:Int get() = when(this){ | |
is Cons ->when(val t = tail()!!){ | |
is Cons ->t.size + 1 | |
is Nil -> 1 | |
} | |
is Nil -> 0 | |
} | |
} | |
inline fun <ITEM:Any> WList<ITEM>.toList():List<ITEM> = fold(listOf()){ acc, it->acc + it} | |
inline fun <ITEM:Any> WList<ITEM>.setHead(item:ITEM): WList<ITEM> = when(this){ | |
is Cons -> Cons(item, tail) | |
is Nil -> this | |
} | |
inline fun <ITEM:Any> WList<ITEM>.setHeadW(item:Wrap<ITEM>): WList<ITEM> = when(this){ | |
is Cons -> item()?.let{Cons(it, tail)} ?: WList() | |
is Nil -> this | |
} | |
inline fun <ITEM:Any> WList<ITEM>.addFirst(item:ITEM): WList<ITEM> = when(this){ | |
is Cons -> Cons(item, W{this}) | |
is Nil -> this | |
} | |
inline fun <ITEM:Any> WList<ITEM>.addFirstW(item:Wrap<ITEM>): WList<ITEM> = when(this){ | |
is Cons -> item()?.let{Cons(it, W(this))} ?: WList() | |
is Nil -> this | |
} | |
//** base-----------------------------------------------------------------*/ | |
tailrec fun <ITEM:Any, ACC:Any> WList<ITEM>.foldW(acc:Wrap<ACC>, block:(Wrap<ACC>, ITEM)->Wrap<ACC>):Wrap<ACC> | |
= when(this){ | |
is Cons-> tail.getOrFailEffect{return W(it)}.foldW(block(acc, head).failEffect{return W(it)}, block) | |
is Nil-> acc | |
} | |
tailrec fun <ITEM:Any, ACC:Any> WList<ITEM>.fold(acc:ACC, block:(ACC, ITEM)->ACC):ACC | |
= when(this){ | |
is Cons-> tail.getOrFailEffect{throw it}.fold(block(acc, head), block) | |
is Nil-> acc | |
} | |
@PublishedApi internal tailrec fun <ITEM:Any, ACC:Any> WList<ITEM>._foldIndexed(index:Int, acc:ACC, block:(Int, ACC, ITEM)->ACC):ACC | |
= when(this){ | |
is Cons ->{ | |
tail.getOrFailEffect{throw it}._foldIndexed(index + 1, block(index, acc, head), block) | |
} | |
is Nil -> acc | |
} | |
inline fun <ITEM:Any, ACC:Any> WList<ITEM>.foldIndexed(base:ACC, noinline block:(Int, ACC, ITEM)->ACC):ACC | |
= _foldIndexed(0, base, block) | |
@PublishedApi internal tailrec fun <ITEM:Any, ACC:Any> WList<ITEM>._foldIndexedW(index:Int, acc:Wrap<ACC>, block:(Int, Wrap<ACC>, ITEM)->Wrap<ACC>):Wrap<ACC> | |
= when(this){ | |
is Cons ->tail.getOrFailEffect{return W(it)}._foldIndexedW(index + 1, block(index, acc, head).failEffect{return W(it)}, block) | |
is Nil -> acc | |
} | |
inline fun <ITEM:Any, ACC:Any> WList<ITEM>.foldIndexedW(base:Wrap<ACC>, noinline block:(Int, Wrap<ACC>, ITEM)->Wrap<ACC>):Wrap<ACC> | |
= _foldIndexedW(0, base, block) | |
inline fun <ITEM:Any> WList<ITEM>.reverseW(): Wrap<WList<ITEM>> | |
= foldW(W(WList())){ acc, it->W{Cons(it, acc)}} | |
inline fun <ITEM:Any> WList<ITEM>.reverse(): WList<ITEM> | |
= reverseW().getOrFailEffect{throw it} | |
inline fun <ITEM:Any, ACC:Any> WList<ITEM>.foldRight(base:ACC, crossinline block:(ITEM, ACC)->ACC):ACC | |
= reverse().fold(base){ acc, it->block(it, acc)} | |
inline fun <ITEM:Any, ACC:Any> WList<ITEM>.foldRightW(base:Wrap<ACC>, crossinline block:(ITEM, Wrap<ACC>)->Wrap<ACC>):Wrap<ACC> | |
= reverseW().flatMap{it.foldW(base){acc, item->block(item, acc)}} | |
fun <ITEM:Any, ACC:Any> WList<ITEM>.foldRightIndexedW(base:Wrap<ACC>, block:(Int, ITEM, Wrap<ACC>)->Wrap<ACC>):Wrap<ACC> | |
= reverseW().flatMap{it._foldIndexedW(0, base){index, acc, item->block(index, item, acc)}} | |
fun <ITEM:Any, ACC:Any> WList<ITEM>.foldRightIndexed(base:ACC, block:(Int, ITEM, ACC)->ACC):ACC | |
= reverse()._foldIndexed(0, base){index, acc, item->block(index, item, acc)} | |
inline fun <ITEM:Any, OTHER:Any> WList<ITEM>.map(crossinline block:(ITEM)->OTHER): WList<OTHER> | |
= foldRight(WList()){ it, acc->Cons(block(it), W(acc))} | |
inline fun <ITEM:Any, OTHER:Any> WList<ITEM>.flatMap(noinline block:(ITEM)->WList<OTHER>):WList<OTHER> | |
= foldRight(WList()) { it, acc -> | |
when(val list = block(it)){ | |
is Cons -> list.foldRight(acc){item, acc2 -> Cons(item, W(acc2)) } | |
is Nil -> acc | |
} | |
} | |
fun <ITEM:Any> WList<WList<ITEM>>.flatten(): WList<ITEM> | |
= foldRight(WList()){it, acc->it.foldRight(acc){ it2, acc2->Cons(it2, W(acc2))}} | |
////** append-----------------------------------------------------------------*/ | |
fun <ITEM:Any> WList<ITEM>.appendW(list:Wrap<WList<ITEM>> = W{WList()}): Wrap<WList<ITEM>> | |
= foldRightW(list){it, acc->W{Cons(it, acc)}} | |
fun <ITEM:Any> WList<ITEM>.append(list:WList<ITEM> = WList()): WList<ITEM> | |
= foldRight(list){it, acc->Cons(it, W(acc))} | |
fun <ITEM:Any> WList<ITEM>.copy():WList<ITEM> = append() | |
operator fun <ITEM:Any> WList<ITEM>.plus(list:WList<ITEM>):WList<ITEM> = append(list) | |
fun <ITEM:Any> WList<ITEM>.copyW():Wrap<WList<ITEM>> = appendW() | |
operator fun <ITEM:Any> WList<ITEM>.plus(list:Wrap<WList<ITEM>>):Wrap<WList<ITEM>> = appendW(list) | |
////** drop----------------------------------------------------------*/ | |
tailrec fun <ITEM:Any> WList<ITEM>._dropWhileIndexed(index:Int, block:(Int, ITEM)->Boolean): WList<ITEM> | |
= if(this is Cons && block(index, head)) tail.getOrFailEffect{return WList()}._dropWhileIndexed(index + 1, block) else this | |
inline fun <ITEM:Any> WList<ITEM>.dropWhileIndexed(noinline block:(Int, ITEM)->Boolean):WList<ITEM> = _dropWhileIndexed(0, block) | |
tailrec fun <ITEM:Any> WList<ITEM>.drop(n:Int = 1): WList<ITEM> | |
= if(n > 0 && this is Cons) tail.getOrFailEffect{return WList()}.drop(n - 1) else this | |
tailrec fun <ITEM:Any> WList<ITEM>.dropWhile(block:(ITEM)->Boolean): WList<ITEM> | |
= if(this is Cons && block(head)) tail.getOrFailEffect{return WList()}.dropWhile(block) else this | |
////** dropLast----------------------------------------------------------*/ | |
@PublishedApi internal tailrec fun <ITEM:Any> WList<ITEM>._dropLastWhileIndexed(index:Int, block:(Int, ITEM)->Boolean):WList<ITEM> | |
= when(this){ | |
is Cons -> if(!block(index, head)) reverse() else tail.getOrFailEffect{return WList()}._dropLastWhileIndexed(index + 1, block) | |
is Nil -> reverse() | |
} | |
fun <ITEM:Any> WList<ITEM>.dropLastWhileIndexed(block:(Int, ITEM)->Boolean):WList<ITEM> = reverse()._dropLastWhileIndexed(0, block) | |
fun <ITEM:Any> WList<ITEM>.dropLastWhile(block:(ITEM)->Boolean):WList<ITEM> = reverse()._dropLastWhileIndexed(0){ _, it->block(it)} | |
fun <ITEM:Any> WList<ITEM>.dropLast(n:Int = 1):WList<ITEM> = reverse()._dropLastWhileIndexed(0){ index, _->index < n} | |
////** utils-----------------------------------------------------------------*/ | |
fun <ITEM:Any> WList<ITEM>.filter(block:(ITEM)->Boolean):WList<ITEM> | |
= foldRight(WList()){ it, acc->if(block(it)) Cons(it, W(acc)) else acc} | |
tailrec fun <ITEM:Any> WList<ITEM>.sliceFrom(item:ITEM): WList<ITEM> | |
= if(this is Cons && head != item) tail.getOrFailEffect{return WList()}.sliceFrom(item) else this | |
tailrec fun <ITEM:Any> WList<ITEM>.slice(from:Int): WList<ITEM> | |
= if(this is Cons && from > 0) tail.getOrFailEffect{return WList()}.slice(from - 1) else this | |
inline fun <ITEM:Any> WList<ITEM>.slice(from:Int, to:Int): WList<ITEM> = slice(from).dropLast(to - from) | |
tailrec fun <ITEM:Any> WList<ITEM>.startsWith(target:WList<ITEM>):Boolean = when(this) { | |
is Cons -> when(target){ | |
is Cons -> if(head == target.head) tail.getOrFailEffect{return false}.startsWith(target.tail.getOrFailEffect{return false}) else false | |
is Nil -> true | |
} | |
is Nil -> target is Nil | |
} | |
tailrec operator fun <ITEM:Any> WList<ITEM>.contains(target:ITEM):Boolean = when(this) { | |
is Cons -> if(head == target) true else target in tail.getOrFailEffect{return false} | |
is Nil -> false | |
} | |
tailrec operator fun <ITEM:Any> WList<ITEM>.contains(target: WList<ITEM>):Boolean = when(this) { | |
is Cons -> when (target) { | |
is Cons -> if(startsWith(target)) true else target in tail.getOrFailEffect{return false} | |
is Nil -> false | |
} | |
is Nil -> target is Nil | |
} | |
inline fun <ITEM:Any, OTHER:Any, RESULT:Any> WList<ITEM>.zipWith(other: WList<OTHER>, noinline block:(ITEM, OTHER)->RESULT): WList<RESULT> { | |
if(this is Nil || other is Nil) return WList() | |
val thisSize = size | |
val otherSize = other.size | |
return if(otherSize > thisSize){ | |
foldRight(WList<RESULT>() to other.dropLast(otherSize - thisSize).reverse()){ it, (acc, target)-> | |
when(target){ | |
is Cons -> Cons(block(it, target.head), W(acc)) to target.tail{WList()} | |
is Nil -> acc to target | |
} | |
} | |
} else { | |
other.foldRight(WList<RESULT>() to dropLast(thisSize - otherSize).reverse()){ it, (acc, target)-> | |
when(target){ | |
is Cons -> Cons(block(target.head, it), W(acc)) to target.tail{WList()} | |
is Nil -> acc to target | |
} | |
} | |
}.first | |
} |
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 fd | |
import kore.wrap.* | |
import org.junit.Test | |
import kotlin.test.assertEquals | |
class WListTest{ | |
@Test | |
fun test1(){ | |
val list = WList(1, 2, 3) | |
val nil = WList<Int>() | |
assertEquals(list.size, 3) | |
assertEquals(nil.size, 0) | |
assertEquals(list.toList(), listOf(1, 2, 3)) | |
assertEquals(list.setHead(5).toList(), listOf(5, 2, 3)) | |
assertEquals(nil.setHead(5).toString(), "Nil") | |
assertEquals(list.setHeadW(W(5)).toList(), listOf(5, 2, 3)) | |
assertEquals(nil.setHeadW(W(5)).toString(), "Nil") | |
assertEquals(list.setHeadW(W(Throwable(""))).toList(), listOf()) | |
assertEquals(nil.setHeadW(W(Throwable(""))).toString(), "Nil") | |
assertEquals(list.fold(""){acc,it->acc + it}, "123") | |
assertEquals(list.foldW(W("")){ acc, item->acc.map{"$it$item"} }(), "123") | |
assertEquals(list.foldW(W("")){ acc, it->W.end() }.ok, null) | |
assertEquals(list.addFirst(4).toList(), listOf(4,1,2,3)) | |
assertEquals(nil.addFirst(4).toString(), "Nil") | |
assertEquals(list.foldIndexed(""){index, acc,it->"$acc$index$it"}, "011223") | |
assertEquals(list.reverse().toList(), listOf(3,2,1)) | |
assertEquals(list.reverseW()()?.toList(), listOf(3,2,1)) | |
assertEquals(list.foldRight(""){it, acc->acc + it}, "321") | |
assertEquals(list.foldRightW(W("")){item, acc->acc.map{"$it$item"}}(), "321") | |
assertEquals(list.foldRightIndexed(""){index, it, acc->"$acc$index$it"}, "031221") | |
assertEquals(list.map{"${it*2}"}.toList(), listOf("2","4","6")) | |
assertEquals(list.flatMap{ if(it != 2) WList(it) else WList() }.toList(), listOf(1,3)) | |
assertEquals(WList(WList(1,2), WList(3,4)).flatten().toList(), listOf(1,2,3,4)) | |
assertEquals(list.appendW()()?.toList(), listOf(1,2,3)) | |
assertEquals(list.append().toList(), listOf(1,2,3)) | |
assertEquals(list.append(WList(4, 5)).toList(), listOf(1,2,3,4,5)) | |
assertEquals((list + WList.Nil).toList(), listOf(1,2,3)) | |
assertEquals((list + WList(4,5)).toList(), listOf(1,2,3,4,5)) | |
assertEquals(list.copy().toList(), listOf(1,2,3)) | |
assertEquals(list.appendW(W(WList(4, 5)))()?.toList(), listOf(1,2,3,4,5)) | |
assertEquals((list + W(WList.Nil))()?.toList(), listOf(1,2,3)) | |
assertEquals((list + W(WList(4,5)))()?.toList(), listOf(1,2,3,4,5)) | |
assertEquals(list.copyW()()?.toList(), listOf(1,2,3)) | |
assertEquals(list.drop(2).toList(), listOf(3)) | |
assertEquals(list.dropWhile { it < 2 }.toList(), listOf(2, 3)) | |
assertEquals(list.dropWhileIndexed { index, it -> index < 1 }.toList(), listOf(2, 3)) | |
assertEquals(list.dropLast().toList(), listOf(1,2)) | |
assertEquals(list.dropLast(2).toList(), listOf(1)) | |
assertEquals(list.dropLastWhile { it > 2 }.toList(), listOf(1,2)) | |
assertEquals(nil.dropLast().toList(), listOf()) | |
assertEquals(nil.dropLast(2).toList(), listOf()) | |
assertEquals(nil.dropLastWhile { it > 2 }.toList(), listOf()) | |
assertEquals(list.dropLastWhileIndexed { index, it ->index < 1}.toList(), listOf(1, 2)) | |
assertEquals(list.filter{it != 2}.toList(), listOf(1,3)) | |
assertEquals(WList(1, 2, 3, 4).filter{it % 2 == 0}.toList(), listOf(2,4)) | |
assertEquals(WList(1, 2, 3, 4).sliceFrom(3).toList(), listOf(3,4)) | |
assertEquals(WList(1, 2, 3, 4).slice(1).toList(), listOf(2,3,4)) | |
assertEquals(WList(1, 2, 3, 4).slice(1,2).toList(), listOf(2,3)) | |
assertEquals(nil.sliceFrom(3).toList(), listOf()) | |
assertEquals(nil.slice(1).toList(), listOf()) | |
assertEquals(nil.slice(1,2).toList(), listOf()) | |
assertEquals(list.startsWith(WList(2,3)), false) | |
assertEquals(list.startsWith(WList(1,2,3)), true) | |
assertEquals(list.startsWith(WList(1,3)), false) | |
assertEquals(WList(1,2,3).startsWith(WList(1,2)), true) | |
assertEquals(list.startsWith(WList()), true) | |
assertEquals(nil.startsWith(WList()), true) | |
assertEquals(nil.startsWith(WList(1,2)), false) | |
assertEquals(WList(1,2) in list, true) | |
assertEquals(WList(2,3) in list, true) | |
assertEquals(WList(1,2,3) in list, true) | |
assertEquals(WList(1,3) in list, false) | |
assertEquals(WList() in list, false) | |
assertEquals(WList(1,3) in nil, false) | |
assertEquals(WList() in nil, true) | |
assertEquals(1 in list, true) | |
assertEquals(2 in list, true) | |
assertEquals(3 in list, true) | |
assertEquals(4 in list, false) | |
assertEquals(1 in nil, false) | |
assertEquals(WList.invoke(1, 2, 3).zipWith(WList.invoke(1,1,1)){ a, b->a + b}.toList(), listOf(2,3,4)) | |
assertEquals(WList.invoke(1, 2).zipWith(WList.invoke(1,1,1)){ a, b->a + b}.toList(), listOf(2,3)) | |
assertEquals(WList.invoke(1, 2, 3).zipWith(WList.invoke(1,1)){ a, b->a + b}.toList(), listOf(2,3)) | |
} | |
} |
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
@file:Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST") | |
package kore.wrap | |
import kotlin.jvm.JvmInline | |
@JvmInline | |
value class Wrap<out VALUE:Any> @PublishedApi internal constructor(@PublishedApi internal val value:Any){ | |
/** R타입을 유지한 상태로 내부의 상태를 바꾸는 연산. 지연연산 모드에서는 계속 지연함수합성이 됨. | |
* map에 전달되는 람다는 throw할 수 있으며 이를 통해 fail상태로 이전시킬 수 있음. | |
*/ | |
inline fun <OTHER:Any> map(crossinline block:(VALUE)->OTHER):Wrap<OTHER> = when(value){ | |
is Throwable -> this as Wrap<OTHER> | |
is Thunk<*> -> Wrap(Thunk{ | |
val v = value.invoke() | |
if(v is Throwable) v else block(v as VALUE) | |
}) | |
else -> Wrap(block(value as VALUE)) | |
} | |
/** 최초의 값을 람다로 지정하지 않아도 이후 지연연산하게 변경함*/ | |
inline fun <OTHER:Any> mapLazy(crossinline block:(VALUE)->OTHER):Wrap<OTHER> = when(value){ | |
is Throwable -> this as Wrap<OTHER> | |
is Thunk<*> -> Wrap(Thunk{ | |
val v = value.invoke() | |
if(v is Throwable) v else block(v as VALUE) | |
}) | |
else -> Wrap(Thunk{block(value as VALUE)}) | |
} | |
inline fun <OTHER:Any, ORIGIN:Any> List<ORIGIN>.flatMapList( block:(ORIGIN)->Wrap<OTHER>):Wrap<List<OTHER>>{ | |
return W(fold(ArrayList(size)){acc, it-> | |
block(it).isEffected{acc.add(it)}?.let {return W(it)} | |
acc | |
}) | |
} | |
inline fun <OTHER:Any> List<String>.flatMapListToMap( block:(key:String, value:String)->Wrap<OTHER>):Wrap<HashMap<String,OTHER>>{ | |
val result:HashMap<String, OTHER> = hashMapOf() | |
var key:String? = null | |
var i = 0 | |
while(i < size){ | |
val it = get(i) | |
if(key == null) key = it | |
else{ | |
block(key, it).isEffected{result[key!!] = it}?.let {return W(it)} | |
key = null | |
} | |
i++ | |
} | |
return W(result) | |
} | |
/** map내에서 오류발생 가능성이 있다면 flatMap을 사용해야 함. */ | |
inline fun <OTHER:Any> flatMap(crossinline block:Wrap<VALUE>.(VALUE)->Wrap<OTHER>):Wrap<OTHER> = when(value){ | |
is Throwable -> this as Wrap<OTHER> | |
is Thunk<*> ->{ | |
val v = value.invoke() | |
if(v is Throwable) W(v) else block(v as VALUE) | |
} | |
else -> block(value as VALUE) | |
} | |
/** flatMap이 무조건 지연평가됨. */ | |
inline fun <OTHER:Any> flatMapLazy(crossinline block:Wrap<VALUE>.(VALUE)->Wrap<OTHER>):Wrap<OTHER> = when(value){ | |
is Throwable -> this as Wrap<OTHER> | |
is Thunk<*> -> Wrap(Thunk{ | |
val v = value.invoke() | |
if(v is Throwable) v else block(v as VALUE).value | |
}) | |
else -> Wrap(Thunk{block(value as VALUE).value}) | |
} | |
/** 실패값을 반드시 복원할 수 있는 정책이 있는 경우 복원용 람다를 통해 현재 상태를 나타내는 예외로부터 값을 만들어냄. 지연연산이 해소됨 */ | |
inline operator fun invoke(block:(Throwable)-> @UnsafeVariance VALUE):VALUE = when(value) { | |
is Throwable -> block(value) | |
is Thunk<*> ->{ | |
val v = value.invoke() | |
if(v is Throwable) block(v) else v | |
} | |
else -> value | |
} as VALUE | |
/** 정상인 값은 반환되지만 비정상인 값은 null이 됨. 지연연산 설정 시 이 시점에 해소됨*/ | |
inline operator fun invoke():VALUE? = when(value){ | |
is Throwable -> null | |
is Thunk<*> ->{ | |
val v = value.invoke() | |
if(v is Throwable) null else v as VALUE | |
} | |
else -> value as VALUE | |
} | |
/** 정상값 Wrap을 얻거나 null을 얻음. 지연연산이 해소된 새로운 Wrap을 얻음*/ | |
inline val ok:Wrap<VALUE>? get() = invoke()?.let{W(it)} | |
/** 오류값 Wrap을 얻거나 null을 얻음. 지연연산이 해소된 새로운 Wrap을 얻음*/ | |
inline val fail:Wrap<VALUE>? get() = when(value){ | |
is Throwable -> this | |
is Thunk<*> ->{ | |
val v = value.invoke() | |
if(v is Throwable) W(v) else null | |
} | |
else -> null | |
} | |
/** value를 얻어 사이드이펙트만 처리한 뒤 자신을 반환함. 지연연산이 해소된 Wrap을 얻음*/ | |
inline fun effect(block:(VALUE)->Unit):Wrap<VALUE>{ | |
block(when(value){ | |
is Throwable -> return this | |
is Thunk<*> ->{ | |
val v = value.invoke() | |
if(v is Throwable) return W(v) | |
v | |
} | |
else -> value | |
} as VALUE) | |
return this | |
} | |
inline fun getOrFailEffect(block:(Throwable)->Nothing):VALUE = when(value){ | |
is Throwable -> block(value) | |
is Thunk<*> ->{ | |
val v = value.invoke() | |
if(v is Throwable) block(v) else v | |
} | |
else -> value | |
} as VALUE | |
inline fun failEffect(block:(Throwable)->Unit):Wrap<VALUE>{ | |
when(value){ | |
is Throwable -> block(value) | |
is Thunk<*> ->{ | |
val v = value.invoke() | |
if(v is Throwable) block(v) | |
} | |
} | |
return this | |
} | |
/** 부수효과가 실행되었다면 null 아니면 Throwable을 반환함. 지연연산이 해소됨 */ | |
inline fun isEffected(block:(VALUE)->Unit= {}):Throwable?{ | |
block(when(value){ | |
is Throwable -> return value | |
is Thunk<*> ->{ | |
val v = value.invoke() | |
if(v is Throwable) return v | |
v | |
} | |
else -> value | |
} as VALUE) | |
return null | |
} | |
} | |
inline fun <ITEM:Any, OTHER:Any, RESULT:Any> Wrap<ITEM>.map2(other:Wrap<OTHER>, block:(ITEM, OTHER)->RESULT):Wrap<RESULT>{ | |
this.isEffected{a-> | |
other.isEffected{b-> | |
return W(block(a,b)) | |
}?.let{ | |
return W(it) | |
} | |
}?.let{ | |
return W(it) | |
} | |
return W.end() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment