typelevel / simulacrum

First class syntax support for type classes in Scala
BSD 3-Clause "New" or "Revised" License
936 stars 61 forks source link

Add support for type classes that abstract over type constructors of 2 type params #6

Open mpilquist opened 9 years ago

mpilquist commented 9 years ago

E.g., bifunctors, profunctors, arrows

drdozer commented 9 years ago

I have a variant on this. were the first type parameter is important, but the rest are just plumbing. For example:

trait Fold2[T, A1, A2] {
  def fold[X](t: T)(
    f1: A1 => X,
    f2: A2 => X): X
}

The typeclass type here is T. The A1 and A2 types are plumbing to make things work. If we had curried type lists, these would be curried.

The code to generate in the companion looks something like this (abridged):

object Fold2 {
  def apply[T, A1, A2](implicit fold: Fold2[T, A1, A2]): Fold2[T, A1, A2] = fold

  trait Ops[T, A1, A2] {
    def typeClassInstance: Fold2[T, A1, A2]
    def self: T
    def fold[X](
        f1: A1 => X,
        f2: A2 => X): X = typeClassInstance.fold(self)(f1, f2)
  }

  trait ToFold2Ops {
    implicit def toFold2Ops[T, A1, A2](target: T)(implicit tc: Fold2[T, A1, A2]): Ops[T, A1, A2] = new Ops[T, A1, A2] {
      val self = target
      val typeclassInstance = tc
    }
  }

  object ops extends ToFold2Ops
}
drdozer commented 9 years ago

And another variant:

  @typeclass trait Equality[T1, T2] {
    @op("===") def equal(lhs: T1, rhs: T2): xs#boolean
    @op("≠") def notEqual(lhs: T1, rhs: T2): xs#boolean
  }

Here, only T1 ever appears on the left, so essentially the same code generation strategy could be used as currently, except that T2 needs to be carried around.

malcolmgreaves commented 9 years ago

+1 I'd love to have this ability!

paulp commented 9 years ago

The typeclass type here is T. The A1 and A2 types are plumbing to make things work. If we had curried type lists, these would be curried.

We do sort of have curried type lists, or at least a way to make the plumbing depend on the one which matters. Since #21 is now fixed this should be viable in practice.

trait Fold2[T] {
  type A1 
  type A2
  def fold[X](t: T)(
    f1: A1 => X,
    f2: A2 => X): X
}
yilinwei commented 8 years ago

@mpilquist I'm going to take a stab at this tomorrow since I want to tidy up the Arrow package in cats.

mpilquist commented 8 years ago

@yilinwei That would be awesome :)

yilinwei commented 8 years ago

A day or two late, but as promised #59.

wrt to the MonadError use case, that is TC[F[_], E] I think that I'll add that in tomorrow because I think that it should be fairly simple.

cvogt commented 8 years ago

Does this mean this ticket can be closed?

Does simulacrum now support this as well?

@typeclass sealed trait AsymEquals[L,R]
cvogt commented 8 years ago

FYI: if this is fixed the Readme also needs to be updated at the very bottom

yilinwei commented 8 years ago

Not yet - I wanted to think a little about the type traversal before continuing - at the moment tit does TC[F[...]]