- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Using existentials to unify type variables in a class constructor.
Sun, 2011-12-04, 19:36
Hi all,
I was just wondering, is it possible to use existentials in a manner similar to the below, in order to unify two type parameters in the constructor of a class?
The below doesn't compile, as the type variable C is not in scope for the constructor parameters, however I hope it's illustrative of what I'm trying to achieve:
class ExistentialUnificationTest[A, B](val tuple1 : (C, A), val tuple2 : (C, B)) { type C = T forSome {type T}}
Essentially, the class ExistentialUnificationTest should be parameterised over the types of the second element of the tuples, however it should enforce that the types of the first elements of each are the same, without introducing an extra type parameter.
Is this possible, or am I misunderstanding something?
Many thanks in advice for any advice you can offer!
Cheers,
Tim
I was just wondering, is it possible to use existentials in a manner similar to the below, in order to unify two type parameters in the constructor of a class?
The below doesn't compile, as the type variable C is not in scope for the constructor parameters, however I hope it's illustrative of what I'm trying to achieve:
class ExistentialUnificationTest[A, B](val tuple1 : (C, A), val tuple2 : (C, B)) { type C = T forSome {type T}}
Essentially, the class ExistentialUnificationTest should be parameterised over the types of the second element of the tuples, however it should enforce that the types of the first elements of each are the same, without introducing an extra type parameter.
Is this possible, or am I misunderstanding something?
Many thanks in advice for any advice you can offer!
Cheers,
Tim
Mon, 2011-12-05, 00:17
#2
Re: Using existentials to unify type variables in a class const
On Sun, Dec 4, 2011 at 7:07 PM, Miles Sabin <miles@milessabin.com> wrote:
I assume you've already tried and rejected the solution which does introduce a third type parameter?
Yes, I have - I have other (rather hacky) reasons for explicitly wanting two type parameters in this case, however, the fact that it unifies any two values of C (as they are subtypes of AnyRef) means it won't work in my case, because, as you suppose below, I'm aiming for a type error if the two aren't instances of the same concrete type.
If it really has to be no more than two type parameters then you'll
have to encode the constraint via an implicit,
This is a really clever approach, thank you! Interestingly, I did come up with a solution using existentials (the problem in my example was only the scope of the type variable C) - however, this suffers from the same drawback as the approach using an extra type parameter, as it unifies any two types of value as AnyRef. However, I could mitigate this with additional constraints, I expect.
Thanks very much for your help!
Tim
On Sun, Dec 4, 2011 at 6:36 PM, Tim Cowlishaw wrote:
> I was just wondering, is it possible to use existentials in a manner similar
> to the below, in order to unify two type parameters in the constructor of a
> class?
>
> The below doesn't compile, as the type variable C is not in scope for the
> constructor parameters, however I hope it's illustrative of what I'm trying
> to achieve:
>
> class ExistentialUnificationTest[A, B](val tuple1 : (C, A), val tuple2 : (C,
> B)) {
> type C = T forSome {type T}
> }
>
> Essentially, the class ExistentialUnificationTest should be parameterised
> over the types of the second element of the tuples, however it should
> enforce that the types of the first elements of each are the same, without
> introducing an extra type parameter.
>
> Is this possible, or am I misunderstanding something?
I assume you've already tried and rejected the solution which does
introduce a third type parameter?
class ExUnifTest[A, B, C](val tuple1 : (C, A), val tuple2 : (C, B))
val e1 = new ExUnifTest((23, "foo"), (23, true)) // C inferred as Int
val e2 = new ExUnifTest((23, "foo"), (2.0, true)) // C inferred as AnyVal
If it really has to be no more than two type parameters then you'll
have to encode the constraint via an implicit,
trait Constraint[A, B]
implicit def constraint[A, B, C] = new Constraint[(C, A), (C, B)] {}
class ExUnifTest[A, B](val tuple1 : A, val tuple2 : B)(implicit ev :
Constraint[A, B])
val e1 = new ExUnifTest((23, "foo"), (23, true)) // OK
val e2 = new ExUnifTest((23, "foo"), (2.0, true)) // Error, but
that's probably what you want
Cheers,
Miles