Skip to content

Instantly share code, notes, and snippets.

@Pooh3Mobi
Last active October 9, 2019 15:32
Show Gist options
  • Save Pooh3Mobi/6093c658fb7ab731815692afc33b72fd to your computer and use it in GitHub Desktop.
Save Pooh3Mobi/6093c658fb7ab731815692afc33b72fd to your computer and use it in GitHub Desktop.
失敗したらMAXまでリトライし、成功したら次の処理を行うKotlinコード、失敗の情報は保持する
package com.example.forloop
sealed class Result<T, E> {
data class Success<T, E>(val t: T) : Result<T, E>()
data class Failure<T, E>(val e: E) : Result<T, E>()
}
sealed class MultiResult<T, E> {
data class Success<T, E>(val t: T, val ers: List<E>?) : MultiResult<T, E>()
data class Failures<T, E>(val msg: String, val ers: List<E>) : MultiResult<T, E>()
}
sealed class Step<out T, E> {
data class Done<out T, E>(val t: T, val ers: List<E>?) : Step<T, E>()
data class Continue<out T, E>(val ers: List<E>) : Step<T, E>()
data class Error<out T, E>(
val msg: String,
val ers: List<E>
) : Step<T, E>()
}
fun <T> (() -> T).runCatching(): Result<T, Throwable> =
try {
Result.Success(this())
} catch (e: Exception) {
Result.Failure(e)
}
fun <T> repeat(
max: Int = 1,
msg: (List<Throwable>) -> String = { "" },
lambda: () -> T
): MultiResult<T, Throwable> {
return (1..max).asSequence()
.fold(
initial = Step.Continue<T, Throwable>(listOf()) as Step<T, Throwable>,
operation = { acc, repeatIndex: Int ->
fun runAndNextStep(continueStep: Step.Continue<T, Throwable>): Step<T, Throwable> =
when (val res = lambda.runCatching()) {
is Result.Success -> Step.Done(res.t, continueStep.ers)
is Result.Failure -> {
val concat = continueStep.ers + res.e
if (repeatIndex >= max) Step.Error(msg(concat), concat)
else Step.Continue(concat)
}
}
if (acc is Step.Continue<T, Throwable>) {
runAndNextStep(acc)
} else {
acc
}
}
)
.takeIf {
it is Step.Done<T, Throwable> || it is Step.Error<T, Throwable>
}
.let { step ->
return@let when (step) {
is Step.Done -> MultiResult.Success(step.t, step.ers)
is Step.Error -> MultiResult.Failures(step.msg, step.ers)
else -> throw IllegalArgumentException()
}
}
}
package com.example.forloop
import java.io.IOException
data class FileData(val number: Int)
fun main(args: Array<String>) {
val fileOperation = { fileData: FileData ->
repeat(
max = 3,
msg = { ers ->"$fileData has some errors: $ers"},
lambda = { treatSomethingAboutFile(fileData) }
)
}
val resultToBoolean = { res: MultiResult<Unit, Throwable> ->
when(res) {
is MultiResult.Success -> true
is MultiResult.Failures -> false
}
}
val sendResult = { file: FileData, isSuccess: Boolean ->
if (isSuccess) sendSuccess(file)
else sendFailure(file)
}
val files = createFileDataList(28)
val res: List<Pair<FileData, Boolean>> = files.asSequence()
.map(fileOperation)
.map(resultToBoolean)
.mapIndexed { index, isSuccess ->
val file = files[index]
sendResult(file, isSuccess)
file to isSuccess
}.toList()
println(res)
}
private fun sendSuccess(file: FileData) {
println("$file is Success")
}
private fun sendFailure(file: FileData) {
println("$file is Failure")
}
private fun createFileDataList(max: Int) =
(0..max).map { FileData(it) }
private fun treatSomethingAboutFile(fileData: FileData) {
Thread.sleep(500)
// 疑似的に5つに1つの割合で失敗するデータ的なやつ
if (fileData.number%5 == 0) {
println("$fileData IOE!")
throw IOException()
}
}
@Pooh3Mobi
Copy link
Author

作業中コード

fun <T> repeat2(
        max: Int = 1,
        msg: (Any) -> String = {""},
        lambda: () -> T
) : MultiResult<T, Throwable> {
    var step: Step2<T, Throwable> = Step2.Cont(Input<Throwable>(null, null))
    for (i in 0..max) {
        when (step) {
            is Step2.Cont -> {
                step = process2(
                        i, max-1, step,
                        { lambda.toThrowableResult() },
                        msg
                )
            }
            is Step2.Res -> return MultiResult.Success(step.t, step.e)
        }
    }
    throw IllegalArgumentException()
}
sealed class Step2<T, E> {
    data class Cont<T, E>(val input: Input<E>) : Step2<T, E>()
    data class Res<T, E>(val t: T? = null, val e: List<E>?, val msg: String? = null) : Step2<T, E>()
}

data class Input<V> (val v: V?, val input: Input<V>?) {
    fun toList(): ArrayList<out V> = recur(this, arrayListOf())
}

private tailrec fun <V> recur(cur: Input<V>, l: ArrayList<V>): ArrayList<V> {
    val cv: V? = cur.v
    if (cv != null) l.add(cv)
    return if (cur.input == null) { l } else { recur(cur.input, l) }
}

fun <T, E> process2(
        i: Int, max: Int, cnt: Step2.Cont<T, E>,
        lambda: () -> Result<T, E>,
        msg: (Any) -> String
): Step2<T, E> {
    val res = lambda()
    return when (res) {
        is Result.Success -> Step2.Res(res.t, cnt.input.toList())
        is Result.Failure -> {
            val concat = Input(res.e, cnt.input)
            val list = concat.toList()
            if (i >= max) {
                Step2.Res(
                        e = list,
                        msg = msg(list)
                )
            } else {
                Step2.Cont(concat)
            }
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment