I believe we made them execute in order in the lat...
# arrow
p
I believe we made them execute in order in the latest revision. In any case I wouldn’t trust
mapN
to execute in order. If order matters, then use
flatMap
g
Thanks @pakoito, hey for contributing to Arrow lib is there any setup doc? I referred this, but felt it’s not comprehensive: https://github.com/arrow-kt/arrow/blob/master/docs/move-to-multi-repo/README.md
p
it used to be that you could go there in one click
right now just find the dock, modify it, and run
./gradlew runAnk
for the whole repo
it should build them
cc @Rachel
g
I will post in the contributors channel as well, thanks
j
Yes this is a fixed bug. Next version will have traverse operate from left to right. The end result order depends on two things: Order of traverse, which will always be left to right from now on and the order of the applicative instance used. Which is also always left to right in 0.15.
g
Thanks @Jannis, any tentative date for the release of 0.15?
r
@Gopal S Akshintala we are working in parallel in the release of 0.10.5 with fixes and new deprecation, 0.11 which is a breaking change with Bifuctor IO and the 1.x version that piggy backs on the lang versioning with meta
They’ll be coming out as available given some people had to switch some priorities due to the current world crisis going around.
@paco is in charge of releasing and he may have more info regarding 0.10.5. In whatever case there is a snapshot for both 0.10.5 and 0.11
if you want to try them out before available
g
Thanks @raulraja, appreciate all the hard work put-in by the Arrow team, you guys are inspiring… 👏🏼@Jannis @pakoito I have taken the 0.11.0-SNAPSHOT and the behavior of
mapN
remains the same as before. May I know which version has the fix available (I was previously on 0.10.5-SNAPSHOT). Thanks
j
There are more ordering issues in
product
from
Apply
. https://github.com/arrow-kt/arrow-core/blob/master/arrow-core-data/src/main/kotlin/arrow/typeclasses/Apply.kt#L300 As you can see it first applies the
other
argument to
this
. Since
tupledN
and
mapN
use that it messes up order. When I checked order last time I must have missed them... Will do a quick pr later today
g
Thanks @Jannis, that shall be a huge help, I am making use of them in a POC
@Jannis /@pakoito Also if
mapN
is fixed to act from left to right, will it also take care of Short-circuting/fail-fast (means if u found a left, rest of them should not be evaluated). Currently,
mapN
evaluates all the expressions, like below
Copy code
@Test
    fun `Left * Right`() {
        val product = Either.applicative<String>().run {
            mapN(
                    "left".left(),
                    getRight()
            ) {}
        }.fix()
        product.fold({ assertEquals("left", it) }, {})
    }

    private fun getRight(): Either<String, String> {
        println("This should not be printed") // vvv But printed
        return "right".right()
    }
Same behavior with
ApplicativeError
as well
Copy code
@Test
    fun `Left * Right`() {
        val product = Either.applicativeError<String>().run {
            mapN(
                    raiseAnError(),
                    getRight()
            ) {}
        }.fix()
        product.fold({ assertEquals("error", it) }, {})
    }

    private fun EitherApplicativeError<String>.raiseAnError(): Either<String, String> {
        println("raising an error")
        return this.raiseError("error")
    } 
    
    private fun getRight(): Either<String, String> {
        println("This should not be printed")
        return "right".right()
    }
p
getRight() is eager, you’re executing it immediately
and you’re passing the result to
mapN
if you want something that’s purely lazy, wrap it into Function0, Eval or IO
g
Ya bad example from my side, but with lazy construts how can I have lazy using
mapN
? It always asks for result isn’t
p
you have to use a lazy datatype like the ones I mentioned above
g
Sorry, but I am still confused, probably let me show you the code where I am struck: https://github.com/overfullstack/ad-hoc-poly/blob/1a6c716e5f2aad6b5ba08b90e2ff7b29d9d8b115/validation-fx/src/main/kotlin/com/validation/rules/UserRules.kt#L33 In here I am using
ApplicativeError
looking for a failfast/shortcircuit, where I don’t want other methods to be called, if one of the method does
raiseError
This is similar to the Either vs Validation example I found on arrow docs
Just FYI, I am using a combination to two effects
ApplicativeError
and
Async
in this code @pakoito
p
use
mapN(later { }, later { })
: https://t.ly/kv8BJ
your types may end up differently, such as
Kind<F, Kind<G, A>>
so you’ll need to flatMap that outer Kind on the caller
or somewhere else
@pakoito, I tried this, but I still can’t achieve a short-circuit, am I doing something wrong?
Copy code
@Test
    fun `IO ApplicativeError`() {
        val product: Either<String, Unit> = IO.async<Nothing>().run {
            Either.applicativeError<String>().run {
                mapN(
                        later { raiseSomeError() },
                        later { justString() }
                ) {}
            }
        }.fix().unsafeRunSyncEither()
        product.fold({ assertEquals("error", it) }, {})
    }

    private fun <S> ApplicativeError<S, String>.raiseSomeError(): Kind<S, String> {
        println("raising an error")
        return raiseError("error")
    }

    private fun <S> ApplicativeError<S, String>.justString(): Kind<S, String> {
        println("This should not be printed")
        return just("just")
    }
p
yes
raiseSomeError returns a Kind
that you don’t do anything about
in the
{}
of the
mapN
check it
you’ll see it returns 2 kinds
g
ya it returns two kinds, and
mapN
needs both their result to do product
so both fns are executed
p
yes and the shortcircuit is for an Either, not for a Kind<F
the Kind is never executed so it won’t short on that raiseError
Copy code
val product: Either<String, Unit> =
            IO.applicativeError().mapN(
              IO.defer { raiseSomeError() },
              IO.defer { justString() }
            ) {}
        }.unsafeRunSyncEither()
g
Thanks @pakoito, now I m struggling to write the other two fns. Sorry to bother, you may respond at ur leisure. Thanks.
Copy code
@Test
    fun `IO ApplicativeError 2`() {
        val product =
                IO.applicativeError<Nothing>().mapN(
                        IO.defer { raiseSomeError() },
                        IO.defer { justString() }
                ) {}.fix().unsafeRunSyncEither()
        
        product.fold({ assertEquals("error", it) }, {})
    }

    private fun <S> ApplicativeError<S, Throwable>.raiseSomeError(): Kind2<S, Throwable, Unit> {
        println("raising an error")
        return raiseError(RuntimeException("error"))
    }

    private fun <S> ApplicativeError<S, String>.justString(): Kind<S, String> {
        println("This should not be printed")
        return just("just")
    }
p
don’t just copypaste my code
I made a mistake and removed the
async()
part that allows calling into the other two 😄
g
Do I need asynchronous here?
p
async()
is the typeclass, with ApplicativeError should be enough
also, IO is not a Kind2
so it may not work at all
g
I m using BIO
p
oh right
then yes 😄
ApplicativeError<S, Throwable>
the error is fixed to
Throwable
too, so do applicativeError<Throwable>()
g
Ya that was a desperate attempt, ideally I would prefer a string
Over throwable
p
ApplicativeError<S, String>
,
applicativeError<String>()
g
Thanks, will try it out tomorrow and get back