jean
09/23/2025, 12:25 PMclass A
class B
class C
class Error
class SomeDependency
fun work1(dependency: SomeDependency): suspend (a: A) -> Either<Error, B> = { a ->
// some work with a
B().right()
}
fun work2(dependency: SomeDependency): suspend (b: B) -> Either<Error, C> = { b ->
// some work with b
C().right()
}
suspend fun featureX(
injectedWork1: suspend (A) -> Either<Error, B>,
injectedWork2: suspend (B) -> Either<Error, C>,
a: A,
): Either<Error, C> =
injectedWork1(a)
.then(injectedWork2)
suspend fun <INPUT, ERROR, OUTPUT> Either<ERROR, INPUT>.then(block: suspend (INPUT) -> Either<ERROR, OUTPUT>): Either<ERROR, OUTPUT> =
when(this) {
is Either.Left -> Either.Left(this.value)
is Either.Right -> block(this.value)
}
With this code, I can have simple low-level-domain functions, work1 and work2 here, and combined them in higher “feature” domain level.
• Should I even try to chain them? I like the style but I could also use a either block with bind from arrow. Are there any downsides to this? If I understood FP good practises correctly, the low level functions should be chained. “The output of a function is the input of the next one”.
• Is it a good practise to have the low-level functions as parameters of the feature? It feels correct to me since I can then easily test it by passing fake implementations.Alejandro Serrano.Mena
09/23/2025, 12:50 PMjean
09/23/2025, 12:54 PMmap and flatmap but I couldn’t pass the next function as a parameter due to injectedWork2 being a suspend function.jean
09/23/2025, 12:55 PMeither {
val b = injectedWork1(a)
injectedWork2(b)
}Youssef Shoaib [MOD]
09/23/2025, 12:55 PMcontext(dependency: SomeDependency, Raise<Error>)
suspend fun work1(a: A): B {
// some work with a
return B()
}
context(dependency: SomeDependency, Raise<Error>)
suspend fun work2(b: B): C {
// some work with b
return C()
}
inline fun featureX(
injectedWork1: (A) -> B,
injectedWork2: (B) -> C,
a: A,
): C =
injectedWork2(injectedWork1(a))
And your featureX is just normal function compositionjean
09/23/2025, 1:00 PMcontext function to inject all the dependencies in featureX. Fine if it’s one or two, but I have some cases up to 5 or more. I felt it creep a little bit everywhere but I’ll give it another try. Thanks for your feedback!Youssef Shoaib [MOD]
09/23/2025, 1:02 PMcontext function will be used only near the start of your application, i.e near main, and hence it should be fine.Kev
09/25/2025, 6:08 AMjean
09/25/2025, 7:36 AM