This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Using existentials to unify type variables in a class constructor.

2 replies
Tim Cowlishaw
Joined: 2011-11-10,
User offline. Last seen 42 years 45 weeks ago.
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
milessabin
Joined: 2008-08-11,
User offline. Last seen 33 weeks 3 days ago.
Re: Using existentials to unify type variables in a class const

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

Tim Cowlishaw
Joined: 2011-11-10,
User offline. Last seen 42 years 45 weeks ago.
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

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland