ok, so in that other method, same question
# arrow
s
ok, so in that other method, same question
b
yes, same question: why require the update logic to depend on the validation logic in some fashion?
s
ok forget "update" for a second
some function that accepts subscription must validate subscription and then call some other method with it
r
normally validation is done previous to piping another function and if those produce effects and you want to have such a flow that means either:
Copy code
suspend validateAndEffect(): ValidatedNel<Error, A>
or
Copy code
fun validateAndEffect(): IO<ValidatedNel<Error, A>>
s
ok its coming together
is there a binding for validated ?
r
no, there is no monad but all you need is
map
from applicative which supports up to 10 ops
or
tupled
s
well I need to parse something first, which I was using try for
then using that try result inside binding, in a validate method
and then from that doing the effect
r
if you have a contained example in a main we can translate to IO and validated
s
IO is a step too far for what I'm trying to introduce here
b
Eh. if it's Jackson parsing it probably should go in
IO
s
I want to get us onto things like Validated/Try/Either first, no way I can introduce IO across the board just yet
I'll try to do an example I can post
👍 1
b
Validated.toEither().flatMap may accomplish what you're looking for
within those constraints
s
ok, I've got enough to play with at the moment I think
one final Q
One thing I like about Try is that I can just do Try { }
b
since Either is monadic and sequences
s
and it will take care of Success/Failure for me
Is there something like for validated
It's annoying having to do .validNel() / invalidNel on 10 different clauses
b
s
I will ask one more question
I need to keep using the result of my validation
for (a <- xx; b < - foo(a) c <- bar(b)) { }
s
I can't use applicative map because I don't have c without making b
so in scala I would do the for comprehension
which I could do here with Try, hence my original question about Try<Unit>
r
You can create your own function to do all that:
Copy code
fun <A> validate(f () -> A): ValidatedNel<Throwable, A> =
  try { f().validNel() } 
  catch (e: Exception) {   
     e.nonFatalOrThrow().invalidNel()
  }
no need to
Try
try/catch is an expression in Kotlin afterall
s
but I want to use them in a comprehension
so it can short circuit
r
then you need
Either
not validated
b
I'm not sure how Validated could short-circuit in Scala since I think it is also applicative there?
r
because if you get a Throwable you want to bail right?
There is
andThen
for validated which shortcircuits
s
Copy code
fun foo() {
    binding {
      val a = something()
      val b = validate(a)
      val c = copy(b)
      val d = bar(a, b)
      result(d)
    }
  }
r
but it can’t form a lawful monad and that is why it’s not called flatMap
s
In Scala I would use Try's
but we've decided Try<Unit> or Try<Subscription> is not right
r
@sam what are the types for a, b, c and d?
s
whatever you want - some of them mutate the original input, some of them validate, some of them are pure functions just creating a new value like a date from the original date
r
in that case not sure you need
binding
at all
that can be done in the environment syntax
s
they are all now returning ValidatedNel
r
ok
le me see in IDEA
s
Copy code
fun foo() {
      val a = something()
      val b = a.map { validate(a) }
      val c = b.map { copy(b) }
      val d = c.map { bar(a, b) }
      d.map { result(d) }
  }
b
I'm not sure that using FP constructs in the face of impure (mutating) functions is a good idea in general
s
when I say mutating I just mean returning a copy of the data class
b
oh so f: A -> A'
s
so in my last snippet there, the issue is that val d line doesn't work because it needs both b,c
yes
so I can do an applicative map there I suppose
b
wait what is
c.map { bar(a, b) }
supposed to do?
s
applicative.map(a,b) { a,b -> c } I suppose
I was just writing it off the cuff
So it's ok FP style to just go down the list mapping on the validated to get another validated like I've done
r
do you ever plan on accumulating errors or is this always fail fast on first error found?
s
not in this case
fail fast is fine
d
The type for fail fast is
Either<E,T>
s
And an Either<Exception, T> is just Try<T> right
back to square one
😂
d
Either<Exception, T>
isn't getting deprecated though
s
lol
fair does
ok to Either I go
d
Either
is stateless
s
ahhh and the applicative now works too !
I was having issues with it with validatd
d
Validated requires a monoid to be an applicative
(Usually
Nel
)
s
I was using ValidatedNel
but I know it was just me doing something wrong
either is good though
d
(In non-nerd speak, it needs to be able to accumulate errors and it uses
Monoid
so you can fill in the behavior)
s
yeah
even I know what a Monoid is
it's about the only thing I do know
d
lol. I'm currently ripping a bunch of
monoid
code out of a python project
s
Semigroup, Monoid, Group, Albelian Group, Magma
I'm converting a python app to kotlin
______init_____
get lost
r
With fail fast you may use Either:
d
I'm not there yet. I have to get the devs here excited for Kotlin, otherwise we'll wind up with a bunch of code that no one knows how to support
r
Copy code
import arrow.core.Either
import arrow.core.extensions.either.fx.fx
import arrow.core.right

fun something(): Either<Throwable, String> = "something".right()
fun validate(a: String): Either<Throwable, String> = "validate($a)".right()
fun copy(b: String): Either<Throwable, String> = "copy($b)".right()
fun bar (a: String, b: String, c: String): Either<Throwable, String> = "bar($a, $b, $c)".right()
fun result(d: String): Either<Throwable, String> = "result($d)".right()

val result = fx<Throwable, String> {
  val a = !something()
  val b = !validate(a)
  val c = !copy(b)
  val d = !bar(a, b, c)
  !result(d)
}

fun main() {
  println(result) //Right(b=result(bar(something, validate(something), copy(validate(something)))))
}
s
It's all coming together @raulraja
👏 1
d
I don't hate Python but I don't love it either
Oops no,
Nel
has no identity so it's a
Semigroup
that
Validated
wants
My category theory is 100% self taught
s
Right final Q then I'll leave you alone for a bit
I've got 10000 eithers
and from 1 of them I need to map on it, and the fn I pass in returns an option
then I want to use the 10000 eithers and the 1 either<a, option<b>> in applicative
what should I do to flatten/transform the either of option result thing
d
you can use
EitherT
or you can use
flatMap
s
flatMap on either doesn't seem to accept option as a result
d
yeah, but you can convert option to either first
s
yep ok
ah yes I see the ext function
lovely !
d
flat map has to return the same kind of monad
s
yeah I guess in Scala I'm used to a couple of implicit conversions around this
d
Before I figured that out I was sooooooo confused
s
this is fucking brilliant now
d
actually OptionT because OptionT is on the inside
If you don't want to drop
Option
from the type signature
But that requires you to learn about Monad Transformers and that might be a lesson for another day
s
Actually I have used those before from cats
That's a concept I find easy to understand
d
It took me a while to figure that out. I was trying to use them to flatten out my dang monads
Or invert the type order
s
You should see a doctor about that
dang monads
oh no, I can't call a coroutine from within my applicative
d
Need IO for suspensions
s
argh
r
it all comes down to IO xD
d
that's intentional
r
embrace it!
s
there's no way 30 kotlin devs from a Java background gonna start using IO this week
I'm struggling and I've been doing scala for 8 years
Is there an escape hatch for now
r
suspend requires
startCoroutine
and that requires a run loop with latches and shit
s
I guess I can take my final either from the applicative and throw or extract
then call coroutine "update"
r
essentially there is not unless you runblocking
d
You could push suspend to the edge of your code
s
I'm in a suspend function already
r
if you are in a suspend function already then just mark your functions as suspend as well
s
I guess you could mark the function to applicative as inline
then it would work
d
It's not useful to make the library support impure code...
s
ok
d
fx
may be possible
then you might be able to do it without IO
Otherwise you're writing your own FP-to-coroutine bridge
s
I can fold on the either that is returned from the applicative
and call my suspend method in that
Ok I'm happy with all this now, it's pure enough that it's 100000% improvement
top help guys, legends
b
that does remind me, I need to have another brown-bag lunchtime talk on FP here
I introduced Vavr as a bridge and I see code like
as.map(a -> a.foo = "bar")
😕
get generated by my coworkers
d
I can't tell you how many times people have protested "how do you get things done?"
And I'm all "not by violating functor laws!!"
r
@sam for the fun of it if you can come up with a compile final example of what you do I can try to translate it to the most simple way for users with imperative syntax whether that is IO or something else. You may benefit by simply encapsulating the core functions in
Rules
class similar to the error handling example and then just expose a DSL where users are not even aware of the types
d
IO denotes a side effect in the types. Stripping that info from your types because people might balk is... less than ideal
r
but since he is already in suspend and
IO
in the next version comes with
io.suspended
and
<http://suspended.io|suspended.io>
you can go into nesting and out of it
that is in Arrow
IO<A>
and
suspend () -> A
represent the same thing and
IO
includes additional APi’s for resource handling etc which allow nesting and use of things like flatMap, bracketCase etc.
b
I'm with @sam on the slow transition to get coworkers to accept FP and/or Kotlin. Getting them to
IO
is a steep hill to climb, especially in the middle of a high-volume production schedule
r
but you can go back to
suspend
in the next release and erase the IO wrapper from the function return if you don’t want the IO type to be in all the function signatures
@Bob Glamm agreed, but since he is in suspend he can just stay with Either
d
Interesting. Is there a way to do applicative map with a suspend function that pushes the suspend outside the applicative?
Let me try and say that with types
b
yup. Personally I prefer to climb the
IO
hill and leave the signatures in since it's consistent with cats IO and Haskell
r
@Derek Berner yes
NonBlocking.parMap
for example
b
I find the transition between languages easier that way
r
there is a concurrent map operation in the Concurrent type class that deals with suspension
d
Kind<Applicative<*>,suspend () -> A> -> suspend () -> Kind<Applicative<*>,F<A>>
basically push your effect out
threadName
is an effect there
and it’s imperative concurrent and non blocking
with the fx DSL
d
Oh nice. So with Arrow it will be possible to describe effects fully with
suspend
if
IO
is too steep a hill to climb
r
we also have fibers, and par versions of traverse and sequence
Arrow IO is all you need to make pure programs that are async, concurrent and tested so far 4x faster than KotlinX runners for the same programs
also cancelation in Arrow Fx is automatic whereas in coroutines is cooperative
additionally eager coroutines can leak resources by design due to cancellation between the acquire and use phases
IO has solved all those problems in Kotin already but we are still in final design phase
d
👍
r
but the same DSL works with Rx, Flow etc. because it’s all in terms of the Concurrent Effect hierarchy of type classes and IO is just it’s proof
Rx Observable and Single also implement and can suspend effects
s
So in this version (0.9.0) if I want to use a suspended function with
binding {}
I need to use
IO
?
I've got a beautiful for comprehension style flow using binding but I do need to call out to do some IO and that's messing it up
r
yes, suspend is either under IO or you are responsible for launching your own coroutines if you are using coroutines core
IO replaces coroutines core or viceversa
s
so... , I can use IO now and it will work from within
binding {}
or I can wait until 0.10 and then coroutines will magically work from within binding as well ?
d
You still have to have a launch point
IO
or
suspend fun main
or
runBlocking
s
my containing function is suspendable
Binding errors via either, and using IO instead of "side effect IO" are orthogonal to me. I should be able to use Either and so on without being forced to adopt IO effect too.
r
if you are already in suspend you can track effects making your functions suspend
s
I get a restricted suspend error
r
where?
s
if I do something like,
Copy code
binding {
  val (a) = fromEither...
  val (b) = from(a)
  val c = someSuspendFunction(b)
  result(c)
}
so at the moment I am doing this:
Copy code
binding {
  val (a) = fromEither...
  val (b) = from(a)
  val c = runBlocking { someSuspendFunction(b) }
  result(c)
}
A temp workaround for a few days
r
oh I see, that is the binding from Either
s
yes
r
You should use the binding from IO instead:
Copy code
import arrow.effects.extensions.io.fx.fx

fx {
  val a = !effectOrRaise { fromEither }
  val b = !efffectOrRaise { from(a) }
  val c = !effect { someSuspendFunction(b) }
  result(c)
}
s
what is the type of a and b here ?
r
same as in your binding the bound right hand side of either
s
ok
and will !effectOrRaise become hidden in 0.10 ?
I can't justify code like that as it means explaining effects as well as typeclasses
r
because effectOrRaise will shortcircuit IO if it finds a left in
suspend () -> Either<A, B>
there is no type classes in that code but that’s fine, this is an actual limitation of Kotlin
s
ok not typeclasses but data types like Either
r
you can’t perform effects in the Either continuation because Either can’t execute suspension
s
yeah, will that change in 0.10 ?
r
that is why the continuation is restricted
no, that can’t change because that is imposed by the lang not us. We can’t build a run loop runtime on each data type that requires suspension so we only built it in IO
because in Either that loop would have to block the thread
to extract the value
s
what will it look like in 0.10, just the same ?
r
that is why in your example you are force to use
runblocking
In 0.10 Io is bifunctor so it includes
E
and
A
and dependency injection
so you never need Either or Try if you are dealing with effects and there is no nesting
s
so IO is also my either type ?
r
in 0.10 Bifunctor IO includes a parametric user custom error beside understanding Throwable so you can model the entire stack
s
right ok so yeah IO can be used instead of either completely
how close is 0.10 ?
r
exactly
0.10 is about 2 weeks or so
❤️ 1
@simon.vergauwen is working on wrapping it up this week
s
So can I do this in 0.10
Copy code
fx {
  val (a) = someIO...
  val (b) = from(a)
  val c = someSuspendFunction(b)
  result(c)
}
r
basically yes except for the
(a)
syntax
s
what will that become
r
there is a collision with priority
with list
List includes component1
s
ah
r
and it shouldn;t since it’s unsafe
so it just becomes
!fa
or
fa.bind()
up to you, we prefer to bang it!
s
I think the bang is awful personally
no disrepect 🙂
r
non taken, why so?
s
my team would just ask why I am negating the function
s
Also it breaks destructuring. this is not valid
val ((a, b)) = tupled()
r
it’s used in other langs to denote effect application
s
it's not intutitve
Is it used in any language that anyone who is not an FPer will have used?
d
It sounds like your team may not be ready for fp
s
I currently see a trent of
+
as an operator in builders
r
in Kotlin force unbind nullable is
!!
d
Likewise, no disrespect
s
But
+
is used in mutable builders so 🤷‍♂️
s
Absolutely no disrepect taken Derek
r
@simon.vergauwen can that return a value in prefix position?
s
But I feel that you can't have FP experience to be ready for FP ? You have to start somewhere.
d
It's a hard question
The imperative world got functors 15ish years ago, and then quit
r
@sam totally agree, we are torn because calling
bind()
is a pain on each bind when you just want to extract the value
s
I'm far from an expert - as you will have learned today. But some things just click - eithers, binding, etc. Some things are quite complicated. I've been doing Scala for 8 years and I still would never use IO as it just complicates things IMO. This actually looks like it's better than the Scala equiv.
d
That's the thing - for pure FP, you need an algebraic type for your effects
s
yeah but I'm not aiming for pure FP.
r
We can actually change this to function application
s
I'm aiming to go from Spring and Java style code to some FP
Haskell can come later
r
We can just apply IO in the IO continuation if it’s invoke is suspended like this
so it would be
s
99% of Kotliners are going to be Java programmers first, and so according a gradual transition is key.
r
fa()
vs
!fa
or
fa.bind()
s
what if fa is already a function? How does that look
like
val a = fa()()
s
@raulraja yes it can just like
!
r
yeah if it’s a function is annoying
s
I hope my feedback is somewhat useful. I'm your target audience in some way - someone who knows a bit, wants to know more, and has loads to learn.
d
I'm in a similar boat. I'm learning loads about FP through Arrow, but at the same time my job requires me to make my work accessible to inexperienced developers
Won't be using a ton of TCs directly for that reason
s
Yeah
I feel Either's and functional error handling are a brilliant entry into FP
I've got a bunch of code upgraded to using eithers, and now with what I've learned today, binding.
But without coroutine support, it will have to be pulled out, because introducing coroutines (another of my goals) is higher priority.
d
Sounds like it's coming along pretty quick though
s
yep
I'm happy to pepper runBlocking around for now, as this service won't be live for months
as long as I know later on I can remove it