Type-level filtering tuple in Scala 3

294 Views Asked by At

I've been trying to filter a type-level tuple as suggested by the Tuple.filter documentation, but I've been getting the error Type argument Playground.IsString does not conform to upper bound [_] =>> Boolean. Does anyone know what I'm getting wrong?

The expected result is that I should be able to write Filter[("first", 1, "second", 2), IsString] =:= ("first", "second")

Playground example: https://scastie.scala-lang.org/SQzB9zTPT5ueIqOiXfG4KQ

import scala.Tuple.Filter

type IsString[X] = X match {
  case String => true
  case _ => false
}

abstract class TupleFilter {
  val x: Filter[("first", 1, "second", 2), IsString]
}
1

There are 1 best solutions below

3
Dmytro Mitin On

You can either add upper bound

type IsString[X] <: Boolean = X match
  case String => true
  case _      => false

or add a type lambda into intersection type & Boolean

val x: Filter[("first", 1, "second", 2), [t] =>> IsString[t] & Boolean]

The thing is that currently subtyping rules for match types are the following:

  1. S match { P1 => T1 ... Pm => Tm } <: T match { Q1 => U1 ... Qn => Un }

    if S =:= T, m >= n, Pi =:= Qi and Ti <: Ui for i in 1..n

  2. S match { P1 => T1 ... Pn => Tn } <: U

    U <: S match { P1 => T1 ... Pn => Tn }

    if S match { P1 => T1 ... Pn => Tn } reduces to U

  3. (S match { P1 => T1 ... Pn => Tn } <: B) <: B

https://docs.scala-lang.org/scala3/reference/new-types/match-types.html#subtyping-rules-for-match-types

There is no rule S match { P1 => T1 ... Pn => Tn } <: T if Ti <: T for i in 1..n.