Uploaded image for project: 'Scala Programming Language'
  1. Scala Programming Language
  2. SI-6744

It is impossible to pattern match on a case class containing partially applied type constructors

    Details

      Description

      I have a feeling this is not easily fixable, but it looks like it is impossible to pattern match on a type that is parameterized on a type constructor, when that type constructor is instantiated to a type alias or some sort of type level function.

      Here's an example, from a stream processing library I am working on:

      trait Process[F[_,_], A]
      case class Halt[F[_,_],A]() extends Process[F,A]
      case class Emit[F[_,_],A](head: A, tail: Process[F,A]) extends Process[F,A]
      case class Await[F[_,_],X,Y,A](fn: F[X,Y], arg: X, recv: Y => Process[F,A]) extends Process[F,A]
      

      So, a Process can either halt, emit a value, or make an external request of its driver, where the external request is a call to evaluate the 'function' F. As a special case of this, we can constrain the requests to be of a particular type:

      trait F1[A,B]
      case class Get[B]() extends F1[Unit,B]
       
      trait One[A] {
        type f[X,Y] = F1[Unit,A]
      }
      

      Now Process[One[Int]#f, String] is a stream transducer that can only request integer values from its sole input stream (and which emits Strings as its output type). The problem arises when I want to pattern match on a Process[One[A]#f, B]. I get 'constructor cannot be instantiated' errors:

      object Failing {
        val a1 = Await[One[Int]#f,Unit,Int,String](Get[Int](), (), (i:Int) => Halt[One[Int]#f,String]())
        val x: Process[One[Int]#f,String] = a1
        val r = a1 match { case Await(f,x,r) => f }
      }
      

      This gives me:

      <console>:32: error: constructor cannot be instantiated to expected type;
       found   : Await[F,X,Y,A]
       required: Await[[X, Y]F1[Unit,Int],Unit,Int,String]
               val r = a1 match { case Await(f,x,r) => f }
                                       ^
      <console>:32: error: not found: value f
               val r = a1 match { case Await(f,x,r) => f }
      

      I'm guessing this is just the usual limitation that a type constructor will never be inferred as a type level function, however it means that I can't meaningfully pattern match on Process, like if I want to implement piping the output of one process to another:

      def pipe[A,B,C](p: Process[One[A]#f, B])(p2: Process[One[B]#f, C]): Process[One[A]#f, c] = ...
      

      Is the only workaround here to define my own custom extractors?

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                retronym Jason Zaugg
                Reporter:
                pchiusano Paul Chiusano
              • Votes:
                0 Vote for this issue
                Watchers:
                2 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: