Reputation: 515
Suppose I have a type A
. How can I define a type B
in scala which is either Unit
or the tuple (A, B)
?
I want to model a type B[A]
which can be
(), (A, ()), (A, (A, ())), (A, (A, (A, ()))), (..., (A, (A, (A, ())))).
I have seen things like
trait B[A] extends (A, B) {}
or examples in
What does the `#` operator mean in Scala?
but was not able to work with what I found since the terminating Unit
possibility is missing.
Thank you.
Upvotes: 0
Views: 1291
Reputation: 4296
You need to use a sealed trait (alegbraic data type) to encode the possibility with type safety.
See how the HList from shapeless[1] does this..
sealed trait HList
sealed trait HNil extends HList
case object HNil extends HNil
case class ::[+H, +T <: HList](head: H, tail: T) extends HList
@ val xs = 1 :: 2.0 :: "three" :: HNil
xs: Int :: Double :: String :: HNil = 1 :: 2.0 :: three :: HNil
When you say you need it to be either a tuple or a Unit, those are the cases that extend
the sealed trait
. Then you can use exhaustive pattern matching on them.
[1] https://github.com/milessabin/shapeless
Upvotes: 2
Reputation: 1022
How about the following (similar to how List
is defined):
trait NestedTuple[+A]
case class Tup[A](a: A, tail: NestedTuple[A]) extends NestedTuple[A]
case object End extends NestedTuple[Nothing]
val t1: NestedTuple[Int] = End
t1: NestedTuple[Int] = End
val t2: NestedTuple[Int] = Tup(1, Tup(2, End))
t2: NestedTuple[Int] = Tup(1,Tup(2,End))
Upvotes: 6
Reputation: 4017
It looks like a Free Monad. You can take an implementation from scalaz
library or cats
.
Upvotes: -1