SAM and PolyFunction

I was interested to see if dotty’s polyfunction could be used with SAM (single abstract method) instantiation and it seems like it can’t

scala> trait FunctionK[F[_], G[_]] {
     |   def apply[A](f: F[A]): G[A]
     | }
// defined trait FunctionK

scala> def run[F[_], G[_], A](f: F[A])(fn: FunctionK[F, G]): G[A] = fn(f)
def run[F[_$1], G[_$2], A](f: F[A])(fn: FunctionK[F, G]): G[A]

scala> run(List(1)) { [A] => (list: List[A]) => list.headOption }
1 |run(List(1)) { [A] => (list: List[A]) => list.headOption }
  |                                                        ^
  |Found:    Object with PolyFunction {...}
  |Required: FunctionK[F, G]
  |
  |where:    F is a type variable with constraint >: List and <: [_$1] =>> Any
  |          G is a type variable with constraint <: [_$2] =>> Any

I just wanted to say, this would be really nice to have since SAMs with parameters on the single abstract method are really not that unusual, especially in functional programming settings. It would be really nice if we the compiler could see these examples and instantiate a new anonymous instance at the call site.

Note, this example is a bit contrived, but consider the example of:

trait Semigroupal[F[_]] {
  def combine[A, B](fa: F[A], fb: F[B]): F[(A, B)]
}

it would be nice to be able to just do [A,B] => (fa: Option[A], fb: Option[B]) => fa.zip(fb) to make an instance (if Option’s instance wasn’t around for example).

5 Likes

Yup, it’s on my todo list.

6 Likes