How to abstract over type kind?

2019-08-07 11:04发布

问题:

I implemented an TList that could collect any type H. But I've discovered that it could not contain higher order types H[_]. So I copypasted the entire thing and added [_] to respected places.

The though came to my mind. What if I would need to store H[_[_]], H[_[_,_]] or even H[_[_[_]]]. Should I just copy the code any time? Is there any way to abstract over type kindness?

回答1:

In Scala there is no rank-2 polymorphism. It means methods (and moreover functions which are not even polymorphic at all) can't except arguments with universal quantifiers (all universal quantifications should be done on method level). So we can have methods like

def f[A, B[_], C[_[_]]](x: A, y: B[A], z: C[B]) = ???

but not like (pseudocode)

def f(x: [A] A, y: [A1, B[_]] B[A1], z: [B1[_], C[_[_]]] C[B1]) = ???

Also this means we can't substitute type constructor to the place where a specific type is expected (really, a type constructor B[_] can be considered as [A] B[A], C[_[_]]] as [B[_]] C[B] or [[A] B[A]] C[B]).

But to make types and type constructors look more uniformly you can wrap a type constructor with a trait type. For example you can look at the following encoding (it's surely wordy, you have to wrap-unwrap types all the time):

  trait Type

  trait ConcreteType extends Type {
    type T
  }

  trait TypeConstructor[U] extends Type {
    type l[X <: U] <: ConcreteType
  }

  type Type0 = ConcreteType
  type Type1 = TypeConstructor[Type0]
  type Type2 = TypeConstructor[Type1]
  type Type3 = TypeConstructor[Type2]

//  type A = Int

  type A = Type0 {type T = Int}

//  type B[X] = List[X]

  type B = Type1 {
    type l[X <: Type0] = Type0 {type T = List[X#T]}
  }

  trait Functor[F[_]]

//  type C[F[_]] = Functor[F]

  type C = Type2 {
    type l[F <: Type1] = Type0 {
      type T = Functor[
        ({
          type ll[X] = (F#l[Type0 {type T = X}])#T
        })#ll
        ]
    }
  }


  trait Generic[FF[_[_]]]   // like shapeless.Generic1, shapeless.IsHCons1, shapeless.IsCCons1
  // Generic1[F[_], FR[_[_]]], IsHCons1[L[_], FH[_[_]], FT[_[_]]], IsCCons1[L[_], FH[_[_]], FT[_[_]]]
  // Generic1[F, Functor], IsHCons1[L, Monad, Monad], IsCCons1[L, Applicative, Applicative]

//  type D[FF[_[_]]] = Generic[FF]

  type D = Type3 {
    type l[FF <: Type2] = Type0 {
      type T = Generic[
        ({
          type ll[F[_]] = (
            FF#l[Type1 {
              type l[X <: Type0] = Type0 {type T = F[X#T]}
            }]
            )#T
        })#ll
        ]
    }
  }

  import shapeless.{::, HNil}

  type lst = A :: B :: C :: D :: HNil

Some links:

https://wiki.haskell.org/Rank-N_types

https://en.wikibooks.org/wiki/Haskell/Polymorphism#Higher_rank_types

https://apocalisp.wordpress.com/2010/07/02/higher-rank-polymorphism-in-scala/



标签: scala types