Kev
03/22/2024, 12:37 PM@optics
data class Foo(val id: UUID, val name: String, val bars: List<Bar>) {
companion object
}
@optics
data class Bar(val id: UUID, val name: String, val visited: Boolean) {
companion object
}
I get as far as Every.list<Foo>().bars.every(Every.list())
and it bombs out on the second every method with Overload resolution ambiguity. All these functions match.
I’m not sure what exactly I’m doing wrong and the resources on the website don’t go into detail with traversing lists within lists (I don’t see why it should be any different, I must be missing something obvious).Kev
03/22/2024, 1:13 PMYoussef Shoaib [MOD]
03/24/2024, 11:37 AMRaise
doesn't mesh nicely with it because Compose doesn't fully support exceptions. Anyone have some experience with this and knows if there's a way to improve the ergonomics of Compose + Raise?CLOVIS
03/25/2024, 9:53 PMfun logIn(username: String, password: String) = either {
val (validUsername, validPassword) = zipOrAccumulate(
{ withError(LogInFailure::InvalidUsername) { usernameOf(username) } },
{ withError(LogInFailure::InvalidPassword) { passwordOf(password) } },
) { u, p -> u to p }
…further processing…
}
and this overall pattern is quite verbose 😕starke
03/27/2024, 1:25 AMkotlin-inject
to supply the dependencies.
I’m starting to think that using a DI library may not be super compatible with the way that ResourceScope
works, because I can’t really figure out a good way to provide my database dependencies as a Resource
when using kotlin-inject
to provide the dependency instances.
Does anyone have any guidance on whether it makes sense to use something like kotlin-inject
alongside the arrow Resource
management stuff? Any insight would be helpful! Thanks 🙂dave08
03/27/2024, 11:02 AMCLOVIS
03/27/2024, 1:00 PMdave08
03/27/2024, 1:24 PMsealed interface Foo
sealed interface FooForBar : Foo {
val bar: Bar
}
@JvmInline
value class Bar(val value: String) {
companion object {
val EMPTY = Bar("")
}
}
And I need to manage a list of Foos that don't derive from ForForBar and a Map<Bar, ForForBar>
is it a bad practice to keep them both in one map and to use Bar.EMPTY
as the key for the ones deriving only from Foo?dave08
03/28/2024, 10:19 AMvar
when multiple functions return enriched data on the same structure:
var result = getFoo()
result = enrich1(result)
result = enrich2(result)
...
?Filip Piechowski
03/29/2024, 1:30 PMIso
to create deep copies of objects only based on their `Iso`s generated only by the plugin generator?
case: I have two data structured as composed data classes. There are 2 parents, them and their composed in children have the same structure in terms of fields. If there were only classes with primitive properties, or all properties were same types on both classes, then I could just use val b = B.iso.compose(A.iso.reverse())
but it wouldn’t work where children are of other types. Is there something in arrow that wold let me reference to isos of children types to convert types the same way i planned to do with parent types?CLOVIS
03/30/2024, 10:57 AMAlejandro Ramos
04/01/2024, 7:33 AMdata class FooList(val values: Set<Foo>) : Set<Foo> by values {
companion object {
fun bar(fooValues: Set<String>): EitherNel<Foo.FooError, FooList> = either {
FooList(
fooValues.mapOrAccumulate { Foo.fromUser(it).bind() }.bind().toSet()
)
}
}
}
Where Foo.fromUser
returns an Either<FooError, Foo>
I’m trying to iterate through the fooValues and while creating Foo Objects, validating them and adding up the errors. (Have to do it inside Foo for reasons)
My question is, is there a cleaner way to implement this?
I thought I could use map and then bindAll() here but it wasn’t possible, seems like this mapOrAccumulate with two binds is the best option?
Sorry if it’s a stupid question, but thank you in advance for the response! arrowsimon.vergauwen
04/03/2024, 1:39 PMsindrenm
04/03/2024, 7:35 PMonLeft {}
when working with the Raise DSL?
Given the following using when dealing with an API that exposes `Either`s:
fun getIntFromDb(): Either<DbError, Int> = 0.right()
One could “forward” the Either
and also intercept `Left`s for logging or whatever:
fun getInt(): Either<DbError, Int> =
getIntFromDb()
.onLeft { log(it.message) }
However, if the API uses the Raise
DSL, it feels a little more weird:
fun Raise<DbError>.getIntFromDb(): Int = 0
fun Raise<DbError>.getInt(): Int =
withError({
log(it.message)
it
}) { getIntFromDb() }
While writing this, I realized also
could clear some things up, but I'm still curious if this is the Correct™ approach:
fun Raise<DbError>.getInt(): Int =
withError({ it.also { log(it.message) } }) { getIntFromDb() }
Alejandro Ramos
04/05/2024, 6:04 AMAdamW
04/08/2024, 10:13 AMiorNel
and mapOrAccumulate
to produce Ior.Both
? 🤔Marc
04/08/2024, 11:10 AMSlackbot
04/08/2024, 2:46 PMNorbi
04/08/2024, 8:27 PMpublic inline fun <Error, A, B> fold(
@BuilderInference block: Raise<Error>.() -> A,
catch: (throwable: Throwable) -> B,
recover: (error: Error) -> B,
transform: (value: A) -> B,
): B
method has the following remark:
This method should never be wrapped in try/catch as it will not throw any unexpected errorsActually, if the
recover
handler throws an exception it is simply rethrown, so the catch
handler applies only to block
, so the following test succeeds:
data object DivisionByZero
context(Raise<DivisionByZero>)
private fun div(a: Int, b: Int): Int =
if (b != 0) {
a / b
} else {
raise(DivisionByZero)
}
@Test
fun testFoldExceptionHandling() {
try {
fold<DivisionByZero, Int, Int>({
div(1, 0)
}, {
throw IllegalStateException("catch", it)
}, {
throw IllegalStateException("recover: $it")
},
::identity
)
fail()
} catch (e: Exception) {
assertEquals("recover: $DivisionByZero", e.message)
}
}
My questions is: is the documentation stale, or is this an actual semantic bug?Andrea Fabris
04/12/2024, 11:21 AMfun mainFun(): Either<A, B>
where A is a sealed interface. I then call this within another function fun caller(): Either<A, B?>
whose goal is to check if the called mainFun
returns left and if so, depending on the type of the left, return B? or A. It always return B if mainFun
returns B.
Currently I’m using fold like the below, so I’m wondering if there’s a better way to do that?
return mainFun().fold({if(it == SpecialSealedImpl} null.right else it.left) { it.right }
Youssef Shoaib [MOD]
04/12/2024, 9:58 PMCLOVIS
04/16/2024, 12:26 PMDaniel Ciocirlan
04/22/2024, 10:41 AMraceN
combinator and I've just hit a NoClassDefFound
error. I was using Arrow 1.2.4 with kotlinx.coroutines 1.6.4 and looking at the implementation of race
, it seems it's using the experimental select feature which is throwing a ClassNotFound for some SelectImplementation
that it didn't find. Upgrading to kotlinx.coroutines 1.8.0 solved this for me.
Is this expected? Worth enforcing in the library dependencies or at least mentioning in the docs?Slackbot
04/23/2024, 11:27 AMJérémy CROS
04/23/2024, 1:51 PMEither<Error, List<A>>
into Either<Error, List<B>>
So far I have :
call.map { it.map { B(a.value) } }
Seems to me like there should be something simpler but I can't for the life of me find it 😅Alejandro Ramos
04/24/2024, 2:01 AM// say I have something like this in my ktor endpoint
post<Resource>{
applicationService.doSomething.fold(
ifLeft= {call.respond(HttpStatusCode.BadRequest, it)},
ifRight = {call.respond(HttpStatusCode.OK, // it)}
)
}
I was wondering if this is the correct usage because fold is used to transform either into a value of C.
Would it be better to change the order to call.respond(result.fold( ifLeft, ifRight))
?
What about when we deal with side effects? (say we want to log and then respond when its a left)
I suppose we use onLeft
in those cases? (since it takes an action that is (left: A) -> Unit))
result.onLeft {
logger.log
call.respond(400)
}
call.respond(200)
I’ve also seen some people do result.mapLeft{call.respond(400,it)}
and then respond 200 after but I feel like that’s not meant to be used that way..
So, is there a “best practice” in these cases? Any of them work but I want to use them how they’re meant to be used.
Sorry for my lack of knowledge in FP, have a nice day!simon.vergauwen
04/24/2024, 10:41 AMJørund Amsen
04/24/2024, 2:29 PMYoussef Shoaib [MOD]
04/24/2024, 6:44 PMbind
or by
on the shift
• You need to surround the body of reset
in maybe
• You need to surround any side-effect or heavy-calculation in an effect
block
The first 2 issues are Compose limitations around throwing exceptions, but in theory they should be supported eventually
The 3rd one is unavoidable due to how Compose works. Everything inside shift
or effect
will run the proper number of times, but anything outside will run as many times as the continuation is run. It's annoying, but again merely surrounding your code in effect
fixes the issue.Kev
04/25/2024, 6:10 AMarrow.core.raise.DefaultRaise@35415e49
where the mockked and provided first parameters are always different.