Bogdan Vakulenko
Bogdan Vakulenko

Reputation: 3390

Shapless coproduct sub-typing

I'm trying to emulate at least some aspects of union types in scala 2.13.

So far the best approach that meets my needs is coproduct from shapless. The only problem is that subtyping is not working as I expected. Here is an example:

import shapeless._

type ISB = Int :+: String :+: Boolean :+: CNil

type ISBSub = Int :+: String :+: CNil

implicitly[ISBSub <:< ISB] // error here

I'm trying to create a method with parameter of type ISB and want this def accept ISBSub as well.

def test(t: ISB) = ???

test(Coproduct[ISBSub](2)) // not working

Is there any way to achieve something like this with coproduct?

Upvotes: 7

Views: 236

Answers (1)

Travis Brown
Travis Brown

Reputation: 139038

Given Shapeless's encoding of coproducts, it's not possible for this kind of subset relationship to be the same as subtyping. Instead there's a type class that provides evidence that one coproduct is a sub-union of another:

scala> import shapeless._
import shapeless._

scala> type ISB = Int :+: String :+: Boolean :+: CNil
defined type alias ISB

scala> type ISBSub = Int :+: String :+: CNil
defined type alias ISBSub

scala> shapeless.ops.coproduct.Basis[ISB, ISBSub]
res0: shapeless.ops.coproduct.Basis[Int :+: String :+: Boolean :+: shapeless.CNil,Int :+: String :+: shapeless.CNil]{type Rest = Boolean :+: shapeless.CNil} = shapeless.ops.coproduct$Basis$$anon$64@ddd69d2

This type class also allows you to convert values of either coproduct type in either direction:

import shapeless.ops.coproduct.Basis

def shrink[A <: Coproduct, B <: Coproduct](a: A)(implicit ev: Basis[A, B]): Option[B] =
  ev(a).toOption

def enlarge[A <: Coproduct, B <: Coproduct](b: B)(implicit ev: Basis[A, B]): A =
  ev.inverse(Right(b))

And then:

scala> shrink[ISB, ISBSub](Coproduct[ISB](1))
res0: Option[ISBSub] = Some(Inl(1))

scala> enlarge[ISB, ISBSub](Coproduct[ISBSub](1))
res1: ISB = Inl(1)

In general it's worth browsing through the contents of the shapeless.ops packages to get a sense of what kinds of operations are supported for things like coproducts.

Upvotes: 9

Related Questions