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

Log:

FileData(number=0) IOE!
FileData(number=0) IOE!
FileData(number=0) IOE!
FileData(number=0) is Failure
FileData(number=1) is Success
FileData(number=2) is Success
FileData(number=3) is Success
FileData(number=4) is Success
FileData(number=5) IOE!
FileData(number=5) IOE!
FileData(number=5) IOE!
FileData(number=5) is Failure
FileData(number=6) is Success
FileData(number=7) is Success
FileData(number=8) is Success
FileData(number=9) is Success
FileData(number=10) IOE!
FileData(number=10) IOE!
FileData(number=10) IOE!
FileData(number=10) is Failure
FileData(number=11) is Success
FileData(number=12) is Success
FileData(number=13) is Success
FileData(number=14) is Success
FileData(number=15) IOE!
FileData(number=15) IOE!
FileData(number=15) IOE!
FileData(number=15) is Failure
FileData(number=16) is Success
FileData(number=17) is Success
FileData(number=18) is Success
FileData(number=19) is Success
FileData(number=20) IOE!
FileData(number=20) IOE!
FileData(number=20) IOE!
FileData(number=20) is Failure
FileData(number=21) is Success
FileData(number=22) is Success
FileData(number=23) is Success
FileData(number=24) is Success
FileData(number=25) IOE!
FileData(number=25) IOE!
FileData(number=25) IOE!
FileData(number=25) is Failure
FileData(number=26) is Success
FileData(number=27) is Success
FileData(number=28) is Success
[(FileData(number=0), false), (FileData(number=1), true), (FileData(number=2), true), (FileData(number=3), true), (FileData(number=4), true), (FileData(number=5), false), (FileData(number=6), true), (FileData(number=7), true), (FileData(number=8), true), (FileData(number=9), true), (FileData(number=10), false), (FileData(number=11), true), (FileData(number=12), true), (FileData(number=13), true), (FileData(number=14), true), (FileData(number=15), false), (FileData(number=16), true), (FileData(number=17), true), (FileData(number=18), true), (FileData(number=19), true), (FileData(number=20), false), (FileData(number=21), true), (FileData(number=22), true), (FileData(number=23), true), (FileData(number=24), true), (FileData(number=25), false), (FileData(number=26), true), (FileData(number=27), true), (FileData(number=28), true)]

Process finished with exit code 0

@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