Scala 3 provides polymorphic functions and Tuples similar to shapeless HList
:
scala> 1 *: "foo" *: Tuple()
val res0: (Int, String) = (1,foo)
scala> val f: ([T] => T => Option[T]) = [T] => (v: T) => Some(v)
val f: PolyFunction{apply: [T](x$1: T): Option[T]} = <function1>
scala> res0.map(f)
val res1: Option[Int] *: Option[String] *: EmptyTuple = (Some(1),Some(foo))
How could we reimplement the following shapeless example using Scala 3 functionality?
import poly._
object choose extends (Set ~> Option) {
def apply[T](s : Set[T]) = s.headOption
}
scala> val sets = Set(1) :: Set("foo") :: HNil
sets: Set[Int] :: Set[String] :: HNil = Set(1) :: Set(foo) :: HNil
scala> val opts = sets map choose
opts: Option[Int] :: Option[String] :: HNil = Some(1) :: Some(foo) :: HNil
In other words, how could we make something like so compile
scala> val choose: ([T] => Set[T] => Option[T]) = [T] => (s: Set[T]) => s.headOption
val choose: PolyFunction{apply: [T](x$1: Set[T]): Option[T]} = <function1>
scala> val sets = Set(1) *: Set("foo") *: Tuple()
val sets: (Set[Int], Set[String]) = (Set(1),Set(foo))
scala> sets.map(choose)
1 |sets.map(choose)
| ^^^^^^
| Found: (choose : PolyFunction{apply: [T](x$1: Set[T]): Option[T]})
| Required: PolyFunction{apply: [t](x$1: t): Any}
Shapeless
map
is quite a bit more magical than Scala 3 tuplemap
, the signature of latter being:Map[Tuple, F]
is a special match type that is basically tuple with every argument type wrapped inF[_]
. The issue is that shape,t => F[t]
that prevents too much fanciness.Except of course,
F
can be a match type itself:There's currently an issue that compiler won't infer polymorphic function from methods. Match types aren't fully type-safe either, e.g. doing
choose("string")
will compile but throw a MatchError. I've also ran into problems with inference of a match type from polymorphic function value, hence the usage ofdef
method.