Reputation: 513
I'm trying to write a homogenous tuple type, somewhat paralleling the built-in tuple type in scala.
I've got the following:
trait HomogeneousTupleFactory [H <: HomogeneousTuple[_, H]] {
def makeHTuple[T] (values: Iterator[T]): HomogeneousTuple[T, H]
}
trait HomogeneousTuple [+T, H <: HomogeneousTuple[_, H]] extends Product {
def getFactory: HomogeneousTupleFactory[H]
def map [U] (fcn: T => U): HomogeneousTuple[U, H] = {
getFactory.makeHTuple(
this.productIterator.map(t => fcn(t.asInstanceOf[T]))
)
}
}
object HTuple2Factory extends HomogeneousTupleFactory[HTuple2[_]] {
def makeHTuple[T] (values: Iterator[T]): HTuple2[T] = {
new HTuple2(values.next, values.next)
}
}
class HTuple2[+T] (t1: T, t2: T) extends Tuple2(t1, t2)
with HomogeneousTuple[T, HTuple2[_]] {
def getFactory = HTuple2Factory
}
I'm trying to get it so that HTuple2.map[U]
returns an HTuple2[U]
instead of a HomogeneousTuple[U, HTuple2]
(which is legitimate and correct, but less convenient), but I can't get it to work.
Anyone have any clues how to do this? Is there a better way than what I'm doing?
Upvotes: 1
Views: 54
Reputation: 692
I don't have time to develop much but it may seem that what you're looking for is
sealed abstract class Nat
final abstract class Z extends Nat
final abstract class S[n <: Nat] extends Nat
trait Vect[n <: Nat, +A] {
def map[B](f : A => B) : Vect[n , B]
}
final case object VNil extends Vect[Z, Nothing] {
def map[B](f : Nothing => B) : Vect[Z, B] = this
}
final case class VCons[n <: Nat, A](head : A, tl : Vect[n, A]) extends Vect[S[n], A] {
def map[B](f : A => B) : Vect[S[n], B] = VCons[n, B](f(head), tl.map(f))
}
implicit final class ConsOps[A](val self : A) extends AnyVal {
def +++[n <: Nat](l : Vect[n, A]) : Vect[S[n], A] = VCons(self, l)
}
type _0 = Z
type _1 = S[_0]
type _2 = S[_1]
type Tuple0[A] = Vect[_0, A]
type Tuple1[A] = Vect[_1, A]
type Tuple2[A] = Vect[_2, A]
def inc[n <: Nat](v : Vect[n , Int]) : Vect[n , Int] = v.map((i : Int) => i + 1)
inc(2 +++ (3 +++ VNil))
Upvotes: 0
Reputation: 3398
I had to move a few things around, but this seems to work:
trait HomogeneousTupleFactory [H[_] <: HomogeneousTuple[_, H]] {
def makeHTuple[T] (values: Iterator[T]): H[T]
}
trait HomogeneousTuple [+T, H[_] <: HomogeneousTuple[_, H]] extends Product {
def getFactory: HomogeneousTupleFactory[H]
def map [U] (fcn: T => U): H[U] = {
getFactory.makeHTuple(
this.productIterator.map(t => fcn(t.asInstanceOf[T]))
)
}
}
object HTuple2Factory extends HomogeneousTupleFactory[HTuple2] {
def makeHTuple[T] (values: Iterator[T]): HTuple2[T] = {
new HTuple2(values.next, values.next)
}
}
class HTuple2[+T] (t1: T, t2: T) extends Tuple2(t1, t2)
with HomogeneousTuple[T, HTuple2] {
def getFactory = HTuple2Factory
}
Basically you needed the H type param in HomogeneousTuple to be a higher-kinded type, the rest of the changes flowed out of that.
Upvotes: 2