Where has Functor disappeared from Arrow? In 0.12 ...
# arrow
v
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
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
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
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
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
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
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
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
Wow! You wrote my code for me! Thanks. 😄 👍