Daniel TIefenauer
12/27/2023, 2:43 PMParseError
if the string could not be parsed for some reason).
The function has the following properties
• the input string can be an Int
or a Double
. If the value can be parsed (happy path), a Either.Right<Int>
is returned
• when passing a Double
, it will be ceiled to the next integer value (so "42.1"
will be parsed as 43
)
• Double
, both .
and ,
are accepted as decimal separators. If this condition is not met, a Either.Left<ParseError.InvalidDecimalPoint>
is returned.Double
, the value must be within in the Interval [Int.MIN_VALUE, Int.MAX_VALUE]
. If this condition is not met, a Either.Left<ParseError.ValueTooLow>
resp. a Either.Left<ParseError.ValueTooHigh>
is returned
• If the string could not be parsed for some other reason (e.g. because it contains non-numeric characters), a Either.Left<ParseError.NotANumber>
is returned.
Based on the above constraints, the function's signature is String -> Either<ParseError, Int>
.
I came up with the solution from the code snippet below, but I can't find a way to chain the eithers together. There's also some code duplication. Seems like there's a flatMapLeft
function missing. Or am I missing something? What's the most elegant, Kotlin-idiomatic way to implement this?stojan
12/27/2023, 3:45 PMrecover
-> https://apidocs.arrow-kt.io/arrow-core/arrow.core/recover.html when chaining these eithersstojan
12/27/2023, 3:46 PMintEither.recover { doubleEither }.recover { decimalPointEither }
Daniel TIefenauer
12/27/2023, 3:54 PMimport arrow.core.recover
AdamW
12/27/2023, 7:27 PMeither
builder and catch
to transform exceptions to typed errors, see here for a comprehensive example: https://blog.rockthejvm.com/functional-error-handling-in-kotlin-part-3/
edit: in fact, you probably need to use nested catch
if you want this in a single function. It’s perhaps simpler to split the ”parsers” and then chain them separately, likely with recover
Youssef Shoaib [MOD]
12/27/2023, 9:50 PMInvalidDecimalPoint
and when I should raise NotANumber
. The code here thus doesn't use NotANumber
at all. Regardless, here's how I would do it:Youssef Shoaib [MOD]
12/27/2023, 9:52 PMeither
and Either
types with .bind()
calls when necessary. I personally think the code in toIntBasedOnSpec
is idiomatic Kotlin with Arrow.Daniel TIefenauer
12/28/2023, 8:01 AMInvalidDecimalPoint
and NotANumber
. I omitted it in my latest implementation. I tried to get it down to a single function without contexts (because context receivers show up as experimental and I don't want to use experimental features) and without Nullability (because I don't like the Elvis operator).
So far I got it down to this function, which nests the eithers using pattern matching in a when
clause. However, I was hoping there would be a more readable/fluent way...
Btw: I now pushed the code to my Repo, where there's also an accompanying test suite to check the implementation: https://github.com/tiefenauer/mp-techlunch-kotlin-arrow/blob/main/src/main/kotlin/NumberParseMonad.ktYoussef Shoaib [MOD]
12/28/2023, 8:13 AM