Cats-effect: Using two monad parameters for initialization of concurrent data

Created on 24 Sep 2018  路  8Comments  路  Source: typelevel/cats-effect

Currently there are at least four concurrency primitives, whose initialization delayed in another layer of effect:
Deffered, MVar, Ref and Semaphore
In some real-world applications initialization of such states happens in different monad than actual application logic.
Simple example:

  1. initializing global shared state - create Ref[Task]s and MVar[Task]
  2. switching to serving requests using ReaderT[Task, ApplicationContext] where ApplicationContext could contain some of initialized Ref's and MVar's

    1. using lift on every put, take and modify

This has annoying effect of transforming every invocation of Ref, MVar, Deffered method from Task to the target monad. In case of tagless final style using two functorial type parameters is even more unpleasant.

There are still some considerations:

  • Usually initialize-time effect could be naturally transformed to the run-time one
  • initialize-time effect is needed for .delay only

I can see two solutions here:

  1. Add special constructors like
    scala object MVar{ // ... def create[F[_]: Sync, G[_]: Concurrent](initial: A): F[MVar[G, A]] // ... }

    1. Add conversion members to primitives like

      ```scala

      abstract class MVar[F[_], A]{

      // ...

      def mapKG[_]: MVar[G, A]

      // ...

      }

I'm eager to implement both.

Most helpful comment

I just ran in to a use case for this when working with Scala.js -- specifically, I'd like to create things like Ref[IO, A] in SyncIO so I'm guaranteed to be able to create my refs synchronously. Note the mapK solution doesn't apply to this use case.

All 8 comments

I'm kind of 馃憥 on constructors, but mapK doesn't sound awful.

I generally write a mapK in the companion object rather than on the class, but I'm not opposed.

I generally write a mapK in the companion object rather than on the class, but I'm not opposed.

I would rather make an integration with cats-tagless when it will be ready.

Not sure what cats-tagless does, but introducing extra dependencies in cats-effect is a tough sell. Because it is middle-ware and other libraries depend on it. I'm worried that cats is too fat for example.

I just ran in to a use case for this when working with Scala.js -- specifically, I'd like to create things like Ref[IO, A] in SyncIO so I'm guaranteed to be able to create my refs synchronously. Note the mapK solution doesn't apply to this use case.

If I understood correctly, the majority of #388 reviewers are ok with mapK and some are ok with dual effect constructors and only dual effect can help in @mpilquist 's issue.
So I'm dgoing to do two distinct PR's . One for mapK and one for dual constructors.
Is that right way?

I mean, I think mapK is a good thing to have anyway. :-)

With #392 and #393 being merged I think this one is solved.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

alexandru picture alexandru  路  5Comments

Avasil picture Avasil  路  3Comments

kubukoz picture kubukoz  路  6Comments

cb372 picture cb372  路  4Comments

Daenyth picture Daenyth  路  3Comments