TormentedDan
02/11/2020, 7:51 PMBob Glamm
02/11/2020, 7:59 PMTormentedDan
02/11/2020, 8:31 PMBob Glamm
02/11/2020, 10:10 PMF
- that is, leaving everything as Kind<F, A>
and providing the appropriate (typeclass) lower-bound for F
that the class/trait/method in question requireBob Glamm
02/11/2020, 10:11 PMIO
) for F
at the edge of the worldBob Glamm
02/11/2020, 10:13 PMT
in ReaderT
) or custom combinatorsTormentedDan
02/11/2020, 10:25 PMkyleg
02/12/2020, 3:03 AMMonad<F>
. But I don’t know how to derive a Kind
from that.kyleg
02/12/2020, 5:33 AMfun <F, A> doSomething(): Kind<F, A> = TODO()
fun <F, A> doSomethingElse(): Kind<F, A> = TODO()
fun <F, A> doAComprehension(myMonad: Monad<F>): Kind<F,A> =
myMonad.fx.monad {
doSomething<F, A>().bind()
doSomethingElse<F, A>().bind()
}
Jannis
02/12/2020, 12:30 PMKind<F, A>
, that is impossible unless you know exactly what F
is. The reason is pretty simply: Kind<F, A>
is not a wrapped A
! It is an action that produces an A
with effects (effects meaning things like ForOption = Might be missing value effect
, ListK = Might have multiple effect
, IO = Anything, including side-effects
etc. You can also view this as context, or other metaphors which are all equally bad 😄). Only if you know exactly what F
is you can run those effects and get your A
value out of it. (Option.fold(...)
, Either.fold(...)
, etc) And from some, like List
or IO
you "cannot" even get the value out because it has mutliple values or it has side-effects. In those cases typeclasses are needed to operator over the inside values.
Now if you have a completly polymorphic F, G, H
you cannot compose them unless you have a few typeclasses that add such generic methods like Traverse
(allows Kind<F, Kind<G, A>> => Kind<G, Kind<F, A>>
) and a few others.
And lastly, if you have mutliple of those effects and you find yourself wrapping and unwrapping them constantly, it might be worth taking a look at mtl, but that is quite a bit more complex, but allows you to create stacks like Kind<F, Kind<G, A>> => Kind<Kind<F, G>, A>
which also combines the types in a way and allows for easier use in comprehensions.TormentedDan
02/12/2020, 5:36 PMTormentedDan
02/12/2020, 5:39 PMTormentedDan
02/12/2020, 5:40 PMTormentedDan
02/12/2020, 5:58 PMJannis
02/13/2020, 1:44 PMDoes this have to do with ReaderT and WriterT?I have seen some explanations for these transformers but, tbh I think I'm going too fast. I need to get the basics first xD.Definitly basics first 😄 mtl is a good tool to use when you know how, but it can be hard to understand and in kotlin (until arrow-meta is in use) is not nice to use... Regarding the code: Not sure I understand what exactly the problem is, but a few things that might improve it anyway: • Avoid
val (_) = ...
This will not work as expected in comprehensions, which is why we are deprecating it soon 😕 (The compiler thinks it can just run the coroutine without ever yielding back to the comprehension if the result is ignored)
• instead of attempt().flatMap { e -> e.fold(...) }
why not handleErrorWith { e -> ... }
TormentedDan
02/13/2020, 3:38 PMval (_) = ...
bit? in other words, how do I force an IO to run inside a comprehension without binding it?Jannis
02/13/2020, 3:43 PMbind
instead. Everything else that binds in comprehension is just an alias for that anywayTormentedDan
02/13/2020, 3:46 PM