https://kotlinlang.org logo
#arrow
Title
v

Ville Peurala

09/21/2022, 6:44 AM
Where has Functor disappeared from Arrow? In 0.12 it was there: https://arrow-kt.io/docs/0.12/arrow/typeclasses/functor/ How do I implement a Functor for my own type in 1.1.3?
s

simon.vergauwen

09/21/2022, 6:55 AM
Hey @Ville Peurala, It was deprecated in 0.12.x, and removed in 0.13.x. Functor (& co) was a abstraction that didn't work well in Kotlin, we tried to look for many solutions and alternatives and we ended removing it in favor of the monadic suspend DSL system we have now. Not sure if you've been able to take a deep look at it? We introduced the first version in 0.13.x, refining it in 1.x.x and I think we've nailed it for Arrow 2.x.x which we're actively working on now.
v

Ville Peurala

09/21/2022, 6:56 AM
Thanks for the info @simon.vergauwen. Can you give me a link to some up-to-date documentation about the monadic suspend DSL system?
s

simon.vergauwen

09/21/2022, 6:57 AM
Here is the PR with the design document for Arrow 2.x.x, https://github.com/arrow-kt/arrow/pull/2797 And in similar fashion how we design unwrapped monadic DSLs for a different monad Resource, also known as Managed. https://github.com/arrow-kt/arrow/pull/2786 The current 1.x.x documentation can be found here, https://arrow-kt.io/docs/apidocs/arrow-core/arrow.core.continuations/-effect/
Not sure if that solves your current problem, but I'd be happy to take a closer look at your use-case if you could provide some more details or code 🙂
v

Ville Peurala

09/21/2022, 7:01 AM
Thanks a lot! I can provide some details. I have an interface `Timed<A>`:
```interface Timed<A> {
fun result(): A
fun startMs(): Long
fun endMs(): Long
}```
Now I would like to make
Timed
a Functor so that users could always map overt the result without affecting the timings.
I could just add a function
fun <B> map(fn: (A) -> B): Timed<B>
to my interface but I have the feeling that it is not an optimal solution.
s

simon.vergauwen

09/21/2022, 7:04 AM
This is mostly oriented around monadic DSLs so that implies
bind
or
flatMap
. Since in Kotlin we don't have a need for
Functor
for collections. I.e. you can do
list.map { either.bind() }
safely within a DSL to replace traverse 🎉 So in this case I would opt for adding
map
, or I think you would need to define zip or
Applicative
as well and then you can also implement
Monad
.
The problem for zip is how do you combine
startMs
and
endMs
does it take the earliest
startMs
and the latest
endMs
? 🤔
If these are questions that don't make sense for your use-case I would opt for simply adding the
map
function.
Tip: if you implement it as
inline
you will be able to call
suspend
functions from the lambda, but you'll need to write
map
as an extension function on
Timed<A>
since
inline
functions need to be
final
😉
v

Ville Peurala

09/21/2022, 7:07 AM
Thanks for the ideas. Yeah, the definition of an Applicative for
Timed<A>
would need some thinking about, but I'm not sure yet whether I need it. I might need a Monad too, but I'll start with a Functor now and see where that takes me.
s

simon.vergauwen

09/21/2022, 7:17 AM
I quickly whipped something up quickly.
zip is now
timed { transform(timedA.bind(), timedB.bind(), timedC.bind(), ...) }
and the strategy it applies over combining
startMs
and
endMs
is parameterised.
v

Ville Peurala

09/21/2022, 7:20 AM
Wow! You wrote my code for me! Thanks. 😄 👍
9 Views