Srki Rakic
09/08/2020, 3:33 PM0.11.0-SNAPSHOT
from being stable?CLOVIS
09/09/2020, 3:53 PMwhere
, and that sounds so much perfect for combining typeclasses
https://kotlinlang.org/docs/reference/generics.html#upper-boundsSatyam Agarwal
09/09/2020, 6:36 PMNir
09/09/2020, 7:21 PMplugins {
id 'org.jetbrains.kotlin.jvm' version '1.4.0'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
jcenter()
maven { url "<https://dl.bintray.com/arrow-kt/arrow-kt/>" }
maven { url "<https://oss.jfrog.org/artifactory/oss-snapshot-local/>" } // for SNAPSHOT builds
}
apply plugin: 'kotlin-kapt'
def arrow_version = "0.11.0"
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib"
implementation "io.arrow-kt:arrow-optics:$arrow_version"
implementation "io.arrow-kt:arrow-syntax:$arrow_version"
kapt "io.arrow-kt:arrow-meta:$arrow_version"
}
JimK
09/09/2020, 8:18 PMNir
09/09/2020, 8:19 PM%=
to avoid repeating the variable name, when using a lens to modify something? Current we have something like:
var longVariableName = Foo(Bar(Baz(5)))
longVariableName = Foo.bar.baz.int.modify(longVariableName) { 20 }
Instead, it would be possible to do:
longVariableName %= <http://Foo.bar.baz.int|Foo.bar.baz.int> { 20 }
Obviously any augmented operator works, I just chose modulus, because modulus -> mod -> modify 🙂stojan
09/10/2020, 8:46 AMhandleErrorWith
equivalent of with arrow-fx-coroutines
?pakoito
09/10/2020, 12:24 PMJoram Visser
09/10/2020, 8:34 PMJoram Visser
09/11/2020, 7:53 PMarrow-fx-coroutines
, that it will be a suspended function. Personally I really like to work with `Either`s, so most often I end up with a signature like suspend fun myMeaningfulLogic(): Either<DomainError, MeaningfulResult>
.
When using such functions, you need to fold the returned Either
so that you can create a response that is useful in an HTTP endpoint. And most often, just to be safe, because everything on the JVM can throw `Exception`s, you want to wrap your meaningful logic in an Either.catch
. Which means more folding to come to a usable value.
To simplify the Either.catch
with multiple `Either.fold`s, I created a generic function that can handle any suspended function that returns an Either
and return a desired type of value:
get("/some/http/endpoint") { // This is an example using Ktor.
handle(
logic = { myMeaningfulLogic() },
ifSuccess = { a -> handleSuccess(call, a) },
ifDomainError = { e -> handleDomainError(call, ::log, e) },
ifSystemFailure = { throwable -> handleSystemFailure(call, ::log, throwable) },
ifUnrecoverableState = ::log
)
}
This generic handler is not limited to endpoint implementations. It can handle any message or event in any framework (there is also a handleBlocking variant) and possibly there are more use cases to use it.
Feel free to check it out, see: https://github.com/sparetimedevs/pofpaf. Use it if you like it. Any feedback is welcome.kartoffelsup
09/11/2020, 8:01 PMCLOVIS
09/11/2020, 8:47 PMsort
function that sorts the objects based on their own implementation, and a second sort
function that sorts based on an external comparator” can be applied to many other interfaces, such as Eq, Hash, Print.
If that's the concept, if I wanted to try to implement this in Kotlin, I would go with something like:
infix inline fun <reified O, reified T>.withTypeclass(typeclass: T) =
object : O by this, T by typeclass
I believe that's not legal Kotlin syntax, but I also think it wouldn't be too hard to add this via a compiler plugin (since it's just generating a new object with compile-time known types, I don't expect it to be that hard).
The idea came from the recommendation on the documentation: https://arrow-kt.io/docs/patterns/dependency_injection/#composing-dependencies
This would allow to write code like
val a = Car() withTypeclass someOrderForCars()
listOf(a).sorted() // or similar
To me, this solves all above use-cases, looks like normal Kotlin (pretty close to no code generation, no hidden complexity...). I don't see any negative sides to this approach.
Of course, I'm still a student, and I have a very light background in functional programming, so I expect that there's a lot that's not apparent to me... The Arrow documentation recommends a completely different way (https://arrow-kt.io/docs/typeclasses/intro/), which if I understand correctly has the benefit of not needing a compiler plugin, but it requires to create a split between ‘typeclass' and ‘interface' that I don't see a need for.
KEEP-87 seems to be yet another way of implementing this, which exclusively uses function parameters to do the combination I showed before, which would mean (if I understand correctly), that it wouldn't be able to send an ‘external implementation' to a function not specifically written with that purpose in mind.
KEEP-87 also introduces a way to decide a default external implementation at compile-time, which is yet another concept.
At this point I'm a bit lost on what the pro/cons of each solution are, assuming I'm not comparing pears to oranges... It seems to me like the first solution would be the easiest one to teach to Kotlin developers without FP experience, since it's so similar to what the language already does with Comparable/Comparator, so I guess that there's a good reason this is not what KEEP-87 looks like, but I don't think I have the needed experience to understand why that is...
I'm very curious as to what expert's thought process looks like on these topics, sorry for this wall of text 😅Satyam Agarwal
09/11/2020, 8:49 PMIO
, and I am now converting it in arrow-fx-coroutines
.
Thing that I am not able to get my head around is how `IO`’s edge of the world conditions is taken care of if i use arrow-fx-coroutines
When using IO
, I was doing like this :
sealed class DomainError : Throwable() {
object NotFound : DomainError()
object NullInIO : DomainError()
override fun fillInStackTrace(): Throwable = this
}
and just before sending response to client, I was doing something like :
fun IO<DomainResponse>.send(): Unit {
return this
.attempt()
.flatMap { response ->
when (response) {
is Either.Left -> { check if it is DomainError and send appropriate response, or else log the unknown error and send generic 500 internal server error }
is Either.Right -> { send 200 ok response }
}
}
.suspendCancellable()
}
By doing something like this I was catching all of the exceptions which wasn’t known to me but were thrown under certain unfortunate scenarios. This kind of approach made me aware of holes in my code, and time to time I went back and fixed them to the point that there are no more surprises.
I hoped that BIO<DomainError, A>
would’ve cleaned up DomainError
sealed class by not extending Throwable, and still covering me like IO<Throwable, A>
, but it is reverted.
How can I do this with Either ? Either.catch
gives Either<Throwable, A>
, and from what I’ve read here, whole point was not to use Throwable
with Either
.Satyam Agarwal
09/11/2020, 8:58 PMIO<A>
to suspend -> Either<Throwable, A>
, is this correct :
fun Ds.closeTxn(exitCase: ExitCase<Throwable>): IO<Unit> {
return IO {
when (exitCase) {
is ExitCase.Cancelled -> this.rollback().close()
is ExitCase.Completed -> this.commit().close()
is ExitCase.Error -> this.rollback().close()
}
}.guarantee(IO { this.close() })
}
to
suspend fun Ds.closeTxn(e: arrow.fx.coroutines.ExitCase): Either<Throwable, Unit> {
return guarantee(
{
Either.catch {
when (e) {
is arrow.fx.coroutines.ExitCase.Completed -> this.commit().close()
is arrow.fx.coroutines.ExitCase.Cancelled -> this.rollback().close()
is arrow.fx.coroutines.ExitCase.Failure -> this.rollback().close()
}
}
},
{ Either.catch { this.close() } }
)
}
Satyam Agarwal
09/14/2020, 12:02 AMparMapN
?
interface SomeRepo {
suspend fun getId(someId: Int): Either<Throwable, Int>
suspend fun getName(someName: String): Either<Throwable, String>
}
interface AnotherClass {
val someRepo: SomeRepo
suspend fun <A, B> getResult(someName: String, someId: Int): Either<Throwable, Tuple2<Int, String>> {
return parMapN(
suspend { someRepo.getId(someId) },
suspend { someRepo.getName(someName) }
) { a, b -> a.product { b } }
}
}
the test doesn’t pass, it says This job hasn't completed yet
when i execute getResult
with runBlockingTest
Satyam Agarwal
09/14/2020, 8:45 AMparTupleN
is why this method exists again ? In IO
, parMapN
was deprecated in favor of parTupledN
because the returned type was not aligned with returned type of other apis in the library.
If I use parTupleN
from arrow-fx-coroutines
, I was expecting that if I am giving it 2 methods with Either
return types, it should give me Either<Throwable, Tuple2<A, B>>
, instead it gives me Tuple2<A, B>, which then needs to be producted like I am doing above with parMapN
.Tower Guidev2
09/14/2020, 2:06 PMmitch
09/15/2020, 8:54 AMPHaroZ
09/15/2020, 12:57 PMassertThat(Environment().unsafeRunSync { mySuspendFunToTest(arg1,arg2) })...
2. how to delay the response of a stub method (a database query) ? I've tried kotlinx.coroutines.DelayKt#delay
but it seems a bit strange to use kotlinx.corroutine just for that
3. how to mock a suspend fun ? I've tried Environment().unsafeRunSync {whenever(aMock.aSuspendedFun()) doReturn aResult}
(with the help of com.nhaarman.mockitokotlin2) but it doesn't seem to work
thx for your help & let me know if I miss up some documentation 🙂Marcin Gryszko
09/16/2020, 7:33 PMEnvironment().unsafeRunAsync
but neither IntelliJ nor Gradle via CLI seems to run the arrow-meta annotation processor.
In build.gradle.kts
I have:
plugins {
id("org.jetbrains.kotlin.jvm") version "1.4.10"
kotlin("kapt") version "1.4.10"
}
dependencies {
implementation(platform("io.arrow-kt:arrow-stack:0.11.0"))
implementation("io.arrow-kt:arrow-fx")
implementation("io.arrow-kt:arrow-mtl") // from the 0.10 version
implementation("io.arrow-kt:arrow-fx-mtl") // from the 0.10 version
implementation("io.arrow-kt:arrow-syntax")
kapt("io.arrow-kt:arrow-meta:0.11.0")
}
Is there anything I'm missing from the build configuration? Am I using Environment
correctly?Marius Kotsbak
09/22/2020, 2:11 PMPhani Mahesh
09/22/2020, 4:13 PMNir
09/23/2020, 4:52 PMtim
09/24/2020, 8:16 AMdata class State(val foo: Int = 1)
typealias NextState = State
// ...
val action = Action.Ping()
val next: NextState = state
.dispatch(action)
.save()
// Now maybe i'll grab a value off of next to send back to the user if that makes sense in the current context
//...
So this approach works fine, but I'm finding an increasing number of use cases where I want to return NextState and a Result. And I'd appreciate any feedback on what others think is a good way to handle this or a call out if my approach is bonkers ... still new to FP 🙂
I'm considering two approaches to achieve the above:
• fun <T> dispatch(action: Action): Either<Failure, Tuple2<NextState, T>>
• fun dispatch(action: Action): Either<Failure, NextState>
In this approach I modify State to have non-serialised var that holds the return value: data class State(val foo: Int = 1, var result: Option<Any> = None) { fun <T> getResult(): Option<T> }
Is there a better way of doing this, is there a preferred approach, is this sound? Any thoughts welcome.Marcin Gryszko
09/24/2020, 5:07 PMfun <F> Applicative<F>.combine(
fn1: () -> Kind<F, Any>,
fn2: () -> Kind<F, Any>
): Kind<F, Any> =
fn1().map2(fn2) { (a, b) ->
// do sth with a and b
}
With Arrow 0.11 I'm trying to pass effectful computations as suspend functions. I'm able to combine them using the either
companion:
suspend fun combine(
fn1: suspend () -> Either<Throwable, Any>,
fn2: suspend () -> Either<Throwable, Any>
): Either<F, Any> =
either {
val a = !fn1()
val b = !fn2()
// do sth with a and b
}
If I want to execute the effects concurrently with parMapN
, I'm not able to unwrap Either
values and work with them:
parMapN(fn1, fn2) { a, b ->
// Compile error: Suspension functions can be called only within coroutine body
either {
// same code as in the sequential example
}
}
Is there a way to combine parMapN
with Either comprehensions?Clarence Dimitri Charles
09/27/2020, 1:23 PMsahil Lone
09/28/2020, 2:30 PMDasyel Willems
09/29/2020, 3:19 PMIO
to the new suspend
way
We're calling a third-party method which returns a CompletableFuture<Void>
and before we handled it in the following way
async {
run {
doSomethingAsync() //this returns the CompletableFuture<Void>
}
}
How do I correctly go from that completableFuture to a suspend function which returns an Either<MyError, Unit>
Krystian Rybarczyk
09/30/2020, 8:58 AMBIO
? I have seen a commit by @simon.vergauwen merged into arrow-fx and then I’ve seen it reverted. Is there a rational somewhere on GitHub maybe that I could go through? Or maybe someone would not mind explaining real quick what happened there? 🙂stojan
09/30/2020, 7:15 PMstojan
09/30/2020, 7:15 PMsimon.vergauwen
10/01/2020, 7:13 AMF
. Therefore it's a lot simpler in design since it uses suspend
all over, instead of making the distincinction between Pure
, Infallible
etc
Both Flow
and Stream
provide a pull based mechanism for streaming, but Stream
splits itself in a Pull
API and a Stream
API.
Flow
offers APIs where you bridge different `Flow`'s to build combinators by using a suspend
back-pressured system. (Typically you collect
and re-emit on a different Flow
).
In contrast Stream
offers a functional API where you can inspect/pull elements and the state of the Stream
, but the focus on building custom operators is low since it aims to be a fully featured toolbox like RxJava where all operators live inside the library and user rely on composition.
Therefore Stream
has a mechanism for safely composing streaming resource, which is one of the strongest features of FS2. You can open a resource with Stream.bracket
or Stream.resource
and it automatically extends/closes the scope/resource depending on which compositonal operators are used.
It also works Chunk
based so it's a Stream
that has Array
of elements at its leaves instead of single elements, and it allows you to work in constant space on those `Chunk`s in its API.
RxJava
is a completely different beast on its own since its push
based and also single element.
Not sure if that fully answers your question so be sure to ask follow up questions if you have any!gildor
10/01/2020, 7:19 AMBut why Flow is pull based?is a completely different beast on its own since itsRxJava
based and also single element.push
simon.vergauwen
10/01/2020, 7:22 AMflow {
emit(1)
// Never reaches here until 1 is consumed
emit(2)
}
more desiredTake that with a grain of salt, since some people might find push based more desired 😅 From the perspective of functional programming it's definitely more desired.
gildor
10/01/2020, 7:28 AMstojan
10/01/2020, 7:31 AMsimon.vergauwen
10/01/2020, 7:37 AMIO.bracket
or Resource
with IO
.stojan
10/01/2020, 7:50 AM