Scala types: smallest upper bounds

I am trying to parameterize some methods with very general type parameters.

As an example, in REPL, I first define:

trait Term case class FunctionalTerm[+T <: Term](t: T) extends Term 

Intuitively, the following method accepts Term and FunctionalTerm and returns something with the smallest upper bound type of the passed term type and the FunctionalTerm argument type:

 def ex1[T1 <: Term, T3 <: X, FunctionalTerm[T1] <: X, X <: R, R <: Term](t1: FunctionalTerm[T1], s: T3): R = sys.error("TODO") 

So far so good at REPL.

Then I define ex2 as a convenience function that performs the same operation as ex1 , but with input arguments:

 def ex2[T2 <: Term, T3 <: X, FunctionalTerm[T2] <: X, X <: R, R <: Term](s: T3, t2: FunctionalTerm[T2]): R = ex1(t2,s) 

Trying to define ex2 in the REPL gives the following error:

 error: inferred type arguments [T2,T3,FunctionalTerm,T3,T3] do not conform to method ex1 type parameter bounds [T1 <: Term,T3 <: X,FunctionalTerm[T1] <: X,X <: R,R <: Term] ex1(t2,s) ^ error: type mismatch; found : FunctionalTerm[T2] required: FunctionalTerm[T1] ex1(t2,s) ^ error: type mismatch; found : T3(in method ex2) required: T3(in method ex1) ex1(t2,s) ^ error: type mismatch; found : R(in method ex1) required: R(in method ex2) ex1(t2,s) ^ 

I spent about two days trying to find a solution, and now I'm completely stuck. I can’t find anything else on Google.

Since the list of arguments of type ex2 matches the list of ex1 , but with the replacement of T1 and T2 , I do not understand that this is wrong or how to fix it.

Any help would be greatly appreciated!

Update

The smallest upper bounds were red herring. An example may be further deleted.

In REPL, the following two functions can be defined without errors:

 def ex1[T1 <: Term, FunctionalTerm[T1] <: Term](t1: FunctionalTerm[T1]): Term = sys.error("TODO: ex1") def ex2[T2 <: Term, FunctionalTerm[T2] <: Term](t2: FunctionalTerm[T2]): Term = ex1(t2) 

Represents the optional parameter X I can define the following in the REPL:

 def ex3[T1 <: Term, FunctionalTerm[T1] <: X, X <: Term](t1: FunctionalTerm[T1]): Term = sys.error("TODO: ex3") 

But an attempt subsequently to determine:

 def ex4[T2 <: Term, FunctionalTerm[T2] <: X, X <: Term](t2: FunctionalTerm[T2]): Term = ex3(t2) 

gives an error:

 error: inferred type arguments [T2,FunctionalTerm,Nothing] do not conform to method ex3 type parameter bounds [T1 <: Term,FunctionalTerm[T1] <: X,X <: Term] def ex4[T2 <: Term, FunctionalTerm[T2] <: X, X <: Term](t2: FunctionalTerm[T2]): Term = ex3(t2) ^ error: type mismatch; found : FunctionalTerm[T2] required: FunctionalTerm[T1] def ex4[T2 <: Term, FunctionalTerm[T2] <: X, X <: Term](t2: FunctionalTerm[T2]): Term = ex3(t2) ^ 

So, I think the question will be: why is the parameter X not used in the signature has this effect?

+6
source share
2 answers

I'm not sure that you are experiencing a mistake, but I am sure that you are making your life much more difficult than it should be. You can rely on covariance and unification to do all the hard work for you,

 scala> trait Term defined trait Term scala> case class FunctionalTerm[+T <: Term](t: T) extends Term defined class FunctionalTerm scala> def ex1[T <: Term](t1 : FunctionalTerm[T], s : T) : T = s ex1: [T <: Term](t1: FunctionalTerm[T], s: T)T scala> class A extends Term ; class B extends A ; class C extends A defined class A defined class B defined class C scala> ex1(new FunctionalTerm(new B), new C) res0: A = C@4ceeb514 

Pay attention to the type of output (which is equivalent to R your original more complex definition) ... it A , which is LUB B and C

Now the upside down version is trivial and Just Works,

 scala> def ex2[T <: Term](s : T, t1 : FunctionalTerm[T]) : T = s ex2: [T <: Term](s: T, t1: FunctionalTerm[T])T scala> ex2(new C, new FunctionalTerm(new B)) res1: A = C@522ddcec 
+5
source

I am going to simplify your example (I am using 2.9.1):

 scala> trait Term; case class FunctionalTerm[+T <: Term](t: T) extends Term; defined trait Term defined class FunctionalTerm scala> def ex1[T1 <: Term, T3 <: X, FunctionalTerm[T1] <: X, X <: R, R <: Term](t1: FunctionalTerm[T1], s: T3): R = sys.error("TODO") ex1: [T1 <: Term, T3 <: X, FunctionalTerm[T1] <: X, X <: R, R <: Term](t1: FunctionalTerm[T1], s: T3)R 

Now declare the second method:

 scala> def ex2[T2 <: Term, T3 <: X, FunctionalTerm[T2] <: X, X <: R, R <: Term](s: T3, t2: FunctionalTerm[T2]): R = ex1(t2, s) <console>:11: error: inferred type arguments [T2,T3,FunctionalTerm,T3,T3] do not conform to method ex1 type parameter bounds [T1 <: Term,T3 <: X,FunctionalTerm[T1] <: X,X <: R,R <: Term] def ex2[T2 <: Term, T3 <: X, FunctionalTerm[T2] <: X, X <: R, R <: Term](s: T3, t2: FunctionalTerm[T2]): R = ex1(t2, s) ^ 

A rather suspicious thing (for me) is the inferred types [T2,T3,FunctionalTerm,T3,T3] - in particular, FunctionalTerm . FunctionalTerm is a constructor of type * -> * , but the method expects type * at this position.

I would say that this is (presumably) a mistake, and therefore you should send it to the scala -user mailing list (before raising your ticket) - Adriaan Moors and Miles Sabin is much more likely to get a detailed answer about whether I am right.

+2
source

Source: https://habr.com/ru/post/915927/


All Articles