Search code examples
scalaexistential-typehigher-kinded-typeshigher-rank-types

Is there any way to map over a collection of values of a type parameterized with a higher type?


I read existing questions about how type definitions with parameterized bounds are illegal inside blocks (or something to that effect), but it doesn't help me in my problem:

type Cons[X]

class Higher[C[X] <: Cons[X]]
type AnyHigher = Higher[C] forSome { type C[X] <: Cons[X] }

Seq[AnyHigher]().map { h => h }

compiler:

can't existentially abstract over parameterized type C
Seq[AnyHigher]().map { h => h }

The element type of the input collection is irrelevant, the problem lies only in the return type of the mapping function. Is there any way around this? I tried various refactors: making the mapping function a method, cheating by making the code generic and executing parameterized with AnyHigher, writing my own recursion, but nothing helps.


Solution

  • A workaround is

    Seq[AnyHigher]().map(new (AnyHigher => AnyHigher) {
      override def apply(h: AnyHigher): AnyHigher = h
    })
    

    "can't existentially abstract over parameterized type..."

    Another workaround is to make C[X] a type member rather than type parameter

    type Cons[X]
    
    class Higher {
      type C[X] <: Cons[X]
    }
    object Higher {
      type Aux[C0[X0] <: Cons[X0]] = Higher { type C[X] = C0[X] }
    }
    
    type AnyHigher = Higher
    
    Seq[AnyHigher]().map(h => h)
    

    and use Higher.Aux[C] instead of Higher[C] and Higher instead of Higher[C] forSome { type C[X] <: Cons[X] }.

    http://dotty.epfl.ch/docs/reference/dropped-features/existential-types.html

    https://scalacenter.github.io/scala-3-migration-guide/docs/incompatibilities/dropped-features.html#existential-type

    Existential type is a dropped feature, which makes the following code illegal.

    def foo: List[Class[T]] forSome { type T }
    

    The proposed solution is to introduce an enclosing type that carries a dependent type:

    trait Bar {   
      type T   
      val value: List[Class[T]] 
    }
    
    def foo: Bar