Scala: error: missing parameter type

I am trying to write some library functions to improve basic collections. Most of them went smoothly, but I have a problem with that.

class EnhancedGenTraversableLike[A, Repr <: GenTraversable[A]](self: GenTraversableLike[A, Repr]) { def mapValuesStrict[T, U, R, That](f: U => R)(implicit ev: A <:< (T, U), bf: CanBuildFrom[Repr, (T, R), That]) = { val b = bf(self.asInstanceOf[Repr]) b.sizeHint(self.size) for ((k: T, v: U) <- self) b += k -> f(v) b.result } } implicit def enhanceGenTraversableLike[A, Repr <: GenTraversable[A]](self: GenTraversableLike[A, Repr]) = new EnhancedGenTraversableLike[A, Repr](self) 

Here is what happens when I use it:

 scala> List((1,2),(2,3),(3,4),(2,5)).mapValuesStrict((_:Int).toString) res0: List[(Int, java.lang.String)] = List((1,2), (2,3), (3,4), (2,5)) scala> List((1,2),(2,3),(3,4),(2,5)).mapValuesStrict(x => x.toString) <console>:13: error: missing parameter type List((1,2),(2,3),(3,4),(2,5)).mapValuesStrict(x => x.toString) ^ 

So Scala cannot determine the type of x .

This answer indicates that Scala does not use one parameter to resolve another, but these separate parameter lists can solve the problem. In my case, however, this is not so simple, since type information is found in implicit parameters.

Is there a way around this so that I don't need to specify a type every time I call a method?


Update: Based on Owen's advice, I ended up creating an enriched class specific to passing through pairs:

 class EnrichedPairGenTraversableLike[T, U, Repr <: GenTraversable[(T, U)]](self: GenTraversableLike[(T, U), Repr]) { def mapValuesStrict[R, That](f: U => R)(implicit bf: CanBuildFrom[Repr, (T, R), That]) = { val b = bf(self.asInstanceOf[Repr]) b.sizeHint(self.size) for ((k: T, v: U) <- self) b += k -> f(v) b.result } } implicit def enrichPairGenTraversableLike[T, U, Repr <: GenTraversable[(T, U)]](self: GenTraversableLike[(T, U), Repr]) = new EnrichedPairGenTraversableLike(self) 
+4
source share
1 answer

Yes there is. Let me give you a simpler example. I hope this also works with your more complex use case.

let's say that

 trait Foo[A] class Bar { def methWithImplicits[A,B](f: A => B)(implicit foo: Foo[A]) = null } implicit def fooInt: Foo[Int] = null 

Now you have exactly the problem that you are describing, since

 (new Bar).methWithImplicits(x => x) 

gives the "missing parameter type".

So, what we would like to do is move the implicit parameter β€œbehind” the explicit function, so Scala sees the implicit first. Well, one way we can do this is to add an extra layer of indirection:

 class Bar { def methWithImplicits2[A](implicit foo: Foo[A]) = new { def apply[B](f: A => B) = null } } (new Bar).methWithImplicits2.apply(x => x) 

This works, although the syntax is not so good. One way you might consider sympathetic syntax is to look at your current design and see if you can sneak implicitly at any of the "early" stages. For example, since the mapValuesStrict Method mapValuesStrict makes sense after you implicitly make the object an implicit property, rather than being passed to the method.

But if it’s not convenient in your design, you can use an additional implicit conversion to sneak it back. This is what we would like to do:

 implicit def addFoo[A](bar: Bar)(implicit foo: Foo[A]) = new { def methWithImplicits3[B](f: A => B) = null } 

But, unfortunately, I suspect that this is a mistake in Scala that forces her to look for an implicit value that is too polymorphic, making him complain:

 could not find implicit value for parameter foo: test.Foo[A] 

This only happens when using implicit conversions, so I think this is a mistake. Thus, we can return it even further: (and, requiring -Xexperimental for dependent types of methods):

 trait FooWrapper { type AA val foo: Foo[AA] } implicit def wrapFoo[A](implicit theFoo: Foo[A]) = new FooWrapper { type AA = A val foo = theFoo } implicit def addFoo(bar: Bar)(implicit foo: FooWrapper) = new { def methWithImplicits3[B](f: foo.AA => B) = null } 

And now

 (new Bar).methWithImplicits3(x => x) 

works great;)


Update

In your particular case, I think your best bet is to work with implicit in enhanceGenTraversable , although, alas, the same hack is required to get around a possible error:

 // Notice `ev` is now a field of the class class EnhancedGenTraversableLike[A, Repr <: GenTraversable[A], T, U] (self: GenTraversableLike[A, Repr], ev: A <:< (T, U)) { def mapValuesStrict[R, That](f: U => R)(implicit bf: CanBuildFrom[Repr, (T, R), That]) = { val b = bf(self.asInstanceOf[Repr]) b.sizeHint(self.size) for ((k: T, v: U) <- self) b += k -> f(v) b.result } } // The Hack trait WrappedPairBound[A] { type TT type UU val bound: A <:< (TT, UU) } implicit def wrapPairBound[A,T,U](implicit ev: A <:< (T,U)) = new WrappedPairBound[A] { type TT = T type UU = U val bound = ev } // Take the implicit here implicit def enhanceGenTraversableLike[A, Repr <: GenTraversable[A]] (self: GenTraversableLike[A, Repr])(implicit ev: WrappedPairBound[A]) = new EnhancedGenTraversableLike[A, Repr, ev.TT, ev.UU](self, ev.bound) 
+6
source

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


All Articles