Hi arrow folks, I'm currently working on the FP in...
# arrow
m
Hi arrow folks, I'm currently working on the FP in Kotlin chapter that deals with Monads 🎉 I've gotten to a point where I can't really express what I want to in Kotlin, and was hoping that Arrow could help me out here!
Specifically, I am trying to declare a monad instance for a data type that has two type parameters, namely
State<S, A>
. We can get around this in the short term by specifying a monad instance that is tied to s specific implementation, in other words declare an `IntState<A>`:
Copy code
val intStateMonad = object : Monad<ForIntState> {
    override fun <A> unit(a: A): IntStateOf<A> =
        IntState { s: Int -> Pair(a, s) }

    override fun <A, B> flatMap(
        fa: IntStateOf<A>,
        f: (A) -> IntStateOf<B>
    ): IntStateOf<B> =
        fa.fix().flatMap { a: A -> f(a).fix() }
}
This has the side-effect that
State<S, A>
needs to extend from
IntStateOf<A>
. Fine, but when we introduce a new member to the state monad family, say
doubleStateMonad
, we are now constrained in that
State<S, A>
cannot also extend from
DoubleStateOf<A>
as well! Even if we could, having to keep extending our base data type doesn't scale very well.
Scala allows us to declare type lambdas to get around this problem by giving us flexibility at instantiation of such a monads anonymously:
Copy code
def stateMonad[S] = new Monad[({type f[x] = State[S,x]})#f] {
  def unit[A](a: => A): State[S,A] = State(s => (a, s))
  def flatMap[A,B](st: State[S,A])(f: A => State[S,B]): State[S,B] =
    st flatMap f
}
Sorry for the long-winded explanation 😄, but is there a way to express something like this with Arrow? And if not, some handy workaround for such situations where multiple type parameters exist?
r
This can probably be solved using StateTPartial
What doe the final Scala encoding look like in the example for this chapter? I can try to type to Kotlin
m
@raulraja I was looking at that in the source code, but couldn't find any examples or documentation regarding how to use this.
r
Something important to mention in the monad chapter is also delimited continuations since they subsume all monads
In whatever case it should be doable, and yes there is no examples because we don't promote MTL style since there is usually better alternatives
👍 2
m
The final example in the original book is the one I pasted above for
stateMonad[S]
. I realise that we won't have something like the type lambdas available, but any help here with a workaround would be super appreciated.
s
@marc0der
({type f[x] = State[S,x]})#f
this loosely translates to an anonymous function at the typelevel which creates a type for
State
which partially applies
S
. If we say that
Kind<F, A> == F[A]
,
Kind2<F, A, B> == F[A, B]
and so on. We can say that
Kind
is constructor at the typelevel, which takes
F
and applies
A
to it. The trick however is that `Kind2<F, A, B> ==
Kind<Kind<F, A>, B>
. So you can partially apply type arguments. In you case you want to apply
S
to
ForState
. So
({type f[x] = State[S,x]})#f
is the equivalent of:
typealias StatePartialOf<S> = Kind<ForState, S>
Where
A
can be applied by doing
Kind<StatePartialOf<S>, A>
==
Kind2<ForState, S, A>
==
State<S, A>
.
Now you can partially apply
S
to
StatePartialOf<S>
, and apply
A
in
map
.
Copy code
interface StateMonad<S> : Monad<StatePartialOf<S>> {
  fun <A, B> Kind<StatePartialOf<S>, A>.map(f: (A) -> B): Kind<StatePartialOf<S>, B>
}
🙌🏾 1
Hope that helps 👍
But as Raul mentioned it’s a pattern we’re not actively promoting, since there are other ways of doing things in Kotlin. Replace
Reader/Kleisli
with extension functions. https://gist.github.com/nomisRev/1f91710ebec1709d4ce8059812482624 Or combining
suspend
with
Either
https://github.com/arrow-kt/arrow-fx/tree/master/arrow-fx-coroutines#suspend----eithere-a
m
@simon.vergauwen thanks for your help! This looks like exactly what I'm after, I'll give it a try when I get a chance later on. I'll ask if there is anything else I'm unclear about.
I hear you both about mtl, but the original book simply uses this as an example of what the meaning of a monad holds, not as a recommended approach. I'll certainly make mention of the other approaches too.
👍 2
s
Glad I was able to help!
🙏 2
m
@simon.vergauwen I just implemented this and it works a treat. Thanks again for your help!
🙌 1
s
You’re very welcome! 🙂