zio / zio-prelude

A lightweight, distinctly Scala take on functional abstractions, with tight ZIO integration
https://zio.dev/zio-prelude
Apache License 2.0
455 stars 115 forks source link

Kind projector #216

Open sideeffffect opened 4 years ago

sideeffffect commented 4 years ago

https://github.com/typelevel/kind-projector

Is there a reason we don't use Kind projector and instead, write the type lambdas manually ourselves?

adamgfraser commented 4 years ago

I think it reduces the accessibility of the library. Kind projector or not we need to be doing everything possible to avoid end users having to interact with partially applied types. Using it results in shorter syntax in some cases but also syntax that is not actually Scala and requires people to understand a compiler plugin and how it changes the language specification. I know there have also been issues with Dotty compatibility, though I believe some of them have been resolved. Would prefer not to use until we have it actually in the language in Scala 3.

sideeffffect commented 4 years ago

fair enough

joroKr21 commented 4 years ago

Note that users of the library don't have to use kind-projector. It's also supported in dotty with -Ykind-projector: https://dotty.epfl.ch/blog/2020/02/05/22nd-dotty-milestone-release.html#kind-projector-syntax-support

adamgfraser commented 4 years ago

Understood. It is more an issue for contributors and readers of the code.

nartamonov commented 4 years ago

I'm relatively layman in the world of FP, but at my work we extensively use ZIO and othen FP libs to drive our stuff. So, in my opinion (it may be shared with other novices and not so advanced people like me) definition of the following instance:

  implicit def MapCovariant[K]: Covariant[({ type lambda[+v] = Map[K, v] })#lambda] =
    new Covariant[({ type lambda[+v] = Map[K, v] })#lambda] {
      override def map[A, B](f: A => B): Map[K, A] => Map[K, B] = { map =>
        map.map(entry => (entry._1, f(entry._2)))
      }
    }

would be much more readable and understandble with the syntax of kind projector:

  implicit def MapCovariant[K]: Covariant[Map[K, *]] =
    new Covariant[Map[K,*]] {
      override def map[A, B](f: A => B): Map[K, A] => Map[K, B] = { map =>
        map.map(entry => (entry._1, f(entry._2)))
      }
    }

Just for example. I think that lambda stuff makes code harder to read and reason about. May be it's the matter of habits, dont know. But in our projects we use kind-projector everywhere. More importantly, you can read and understand the purpose of that plugin in the README in about 10 minutes, while learning that lambda syntax is not so easy task: you must search google for various blogposts and so on.

sideeffffect commented 4 years ago

@nartamonov yeah... I'm also beginning to think that not using Kind projector is causing more harm than benefit... If there would be an agreement to change the codebase over to Kind projector syntax, I'd volunteer to do the work -- IntelliJ will make the job dead simple for me, because it has an auto-suggestion which will do the actual rewriting :wink:

lemastero commented 4 years ago

I vote for kind projector if the dotty plays nicely with it.

type lambdas syntax is the most horrible part of Scala (unless sb will teach you how to use them). KindProjector lowers the barrier significantly. You don't need to know that that it exists or that type lambda exists or what is compiler plugin.

It is intuitive to use * in place of the type you want to abstract over.

The only drawback of using KindProjector is when it does not support some crazy features, but there is a slim chance we will go into Kan extensions & Profunctor Monads, etc in zio-prelude.

sideeffffect commented 4 years ago

@lemastero wholeheartedly agree! Sadly, we use variance pervasively, but Dotty doesn't support variance annotations (like +*, -*) yet :crying_cat_face: https://github.com/lampepfl/dotty/issues/7139#issuecomment-565468066

sideeffffect commented 3 years ago

@adamgfraser @neko-kai Actually, I think that now it is a good time to switch to the nice "kind-projector" syntax for type lambdas. It's supported natively by Scala 3.0.0 and now 2.13.6 (blocked on https://github.com/zio/zio-prelude/pull/630 ).

Or is there a reason for us not to use the */+*/-* syntax for cross-compiling for 2.11, 2.12, 2.13 and 3.0?

neko-kai commented 3 years ago

@sideeffffect Yeah, that would be great. One thing is 2.11 support for +_/-_ will not come, so we'd have to drop it. Alternatively, you can write `+_`/`-_` with the backticks - this will work across all versions including 2.11, but will be a bit uglier than +*/-*