The following code will only be an example of a project that due to (nested) higher kinds heavily relies on typeclasses for its DSL.

When reviewing the code keep in mind that this is an example, so I am not relying on libraries like cats even if they might already provide solutions for what I am doing.

With that aside I have some explicit questions about aspects of my code apart from an overall review:

  • What's the correct package structuring e.g. /algebra, /syntax, /ops, /dsl, /implicits, ... and where in that structure do simple case classes (like M or N) go, where typeclasses (like Invertable), where typeclass-instances (like mnInvertable), where implicit classes (like InvertableOps)?
  • Is my use of an implicit class good here, or is there a better way to define .invert on types like M[N[A]]?
  • Should the implicit parameter in the implicit class be moved to def invert instead?
  • What's the naming convention for typeclasses (I used ...able), typeclass instances (I used type + typeclass) and implicit classes (I used typeclass + Ops)?
  • Bonus: Is it possible to define Invertable as context bounds instead of an implicit parameter? (I think not, but who knows!)
// src/main/scala/myproject/algebra/M.scala
case class M[A](value: A)

// src/main/scala/myproject/algebra/N.scala
case class N[A](value: A)

// src/main/scala/myproject/syntax/Invertable.scala
trait Invertable[F[_], G[_]] {
  def invert[A](fga: F[G[A]]): G[F[A]]

// src/main/scala/myproject/implicits/package.scala
implicit val mnInvertable: Invertable[M, N] = new Invertable[M, N] {
  def invert[A](fga: M[N[A]]): N[M[A]] = N(M(fga.value.value))

implicit class InvertableOps[F[_], G[_], A](fga: F[G[A]])(implicit i: Invertable[F, G]) {
  def invert = i.invert(fga)

// Somewhere in the project
M(N(1)).invert // It works!

This question has an open bounty worth +50 reputation from Markus Appel ending tomorrow.

This question has not received enough attention.

Give a good code review, taking into account all points I mentioned in my question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.