Turin
Turin

Reputation: 2250

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.

Upvotes: 0

Views: 116

Answers (2)

Turin
Turin

Reputation: 2250

Why @Dmytro Mitin's answer is the correct one as both type safe, and offering a local solution not needing changes to the types, it is a bit of a mouthful. So, at least temporarily, I opted for introducing a super type and casting:

    sealed trait AnyHigher {
        def apply() :Higher[T] forSome { type T[O] <: Cons[O] } =
            this.asInstanceOf[Higher[T] forSome { type T[O] <: Cons[O] }]
    }
    
    class Higher[T[O] <: Cons[O]] extends AnyHigher

    Seq[AnyHigher]().map(t => t)

It's ugly, but a bit less and it's temoporary until Scala 3, which has wildcard types covering any kinds.

Upvotes: 0

Dmytro Mitin
Dmytro Mitin

Reputation: 51683

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

Upvotes: 2

Related Questions