Hi, is it possible to do something like this on Ar...
# arrow
j
Hi, is it possible to do something like this on Arrow ?
Copy code
either {
    

   val changeType: String

    if (changeType == "do nothing") {
       //leave early, this is not an error
        return Either.Right("leave early)
    }
    ..do some complicated logic and leave
     "quit".right()
  }
r
Hi @Jorge Bo, yes it is possible:
Copy code
enum class ChangeType {
    DoNothing, RealChangeStartsHere
}

suspend fun foo(changeType: ChangeType): Either<Nothing, String> =
    either myLabel@ {
        if (changeType == ChangeType.DoNothing) {
            return@myLabel "done"
        }
        "quit"
    }

suspend fun main() {
    println(foo(ChangeType.DoNothing)) // Either.Right(done)
    println(foo(ChangeType.RealChangeStartsHere)) // Either.Right(quit)  
}
Here
myLabel
is a label for the
either
block lambda which allows you to use it in a
return
. This return can short-circuit up to the labeled boundary based on your logic. This functionality it's not specific to Arrow but part of the Kotlin language. https://kotlinlang.org/docs/returns.html#return-to-labels
s
Besides using
label
you can also use some "functional tricks" to achieve this behavior. You can wrap your
Either.Left
in another
Either
and flatten it with
handleErrorWith
(or
recover
on
alpha
).
Copy code
either<Either<E, String>, String> {
     val changeType: String

    ensure(changeType != "do nothing") { "leave early".right() }
    ..do some complicated logic and leave
     "quit"
}.handleErrorWith { it } //recover { it.bind() }
Since you haven't shown any
E
in your example it's also perfectly fine to do the following if you don't have any
E
type in the left side.
Copy code
val res: String = either<String, String> {
    val changeType: String

    ensure(changeType != "do nothing") { "leave early" }
    ..do some complicated logic and leave
     "quit"
}.merge()
Either.Left
can also be used to short-circuit without being a failure but rather an "early exit" as you need here. We call it a logical failure to represent it means the computation stops, but it's not an "error" perse.
d
Besides
ensure
, which is more concise, shouldn’t
shift
be an alternative in the
EffectScope
? https://arrow-kt.io/docs/apidocs/arrow-core/arrow.core.continuations/-effect-scope/shift.html
s
Not entirely sure what you mean @David, but
ensure
is a DSL similar to
kotlin.require
using
if + shift
. So yes, you can use
shift
as an alternative if you prefer to write explicit
if
statements instead of
ensure
.
d
Yes, exactly. Just clarification that
shift
is the leave early function he was looking for, but agree
ensure
as you mentioned is the way to go here.
j
thanks, both solutions suit my project