higherkindness / droste

recursion schemes for cats; to iterate is human, to recurse, divine

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Unapply seems to fail on Cofree

clayrat opened this issue · comments

Consider this function (adapted from https://jtobin.io/time-traveling-recursion):

def oddIndices[A]: List[A] => List[A] =
  scheme.zoo.histo[ListF[A, ?], List[A], List[A]](
    CVAlgebra[ListF[A, ?], List[A]] {
      case NilF => Nil
      case ConsF(h, _ :< NilF) => List(h)
      case ConsF(h, _ :< ConsF(_, t :< _)) => h :: t
    }
  )

This fails to compile with the following error (corresponds to the ConsF(h, _ :< NilF) case):

Error:(21, 28) pattern type is incompatible with expected type;
 found   : qq.droste.data.list.NilF.type
 required: F[qq.droste.data.Cofree[F,A]] forSome { type A; type F[_]; type F[_]; type A }
        case ConsF(h, _ :< NilF) => List(h)

Apparently it can't figure out that F is ListF[A, ?] here? A workaround is to unwrap manually:

def oddIndices[A]: List[A] => List[A] =
  scheme.zoo.histo[ListF[A, ?], List[A], List[A]](
    CVAlgebra[ListF[A, ?], List[A]] {
      case NilF => Nil
      case ConsF(h, coa) => Cofree.un[ListF[A, ?], List[A]](coa) match {
        case (_, NilF) => List(h)
        case (_, ConsF(_, coa2)) => h :: Cofree.un[ListF[A, ?], List[A]](coa2)._1
      }
    }
  )

I'm wondering if this instead has to do with the typer's inability to widen NilF (extends ListF[Nothing, Nothing]) to ListF[A, ?].

What if we redefine the top level NilF as:

package list
// ...
object `package` { // aka package object `list`
  def NilF[A, B]: ListF[A, B] = ListF.NilF
}
// ...
object ListF {
  // current NilF moved into a narrower scope
  case object NilF extends ListF[Nothing, Nothing]
}

We might also have to add an additional companion for the new top level NilF, along with some boilerplate methods.