1

How would one encode the following constraint in Scala (pseudocode)?

def foo(x: T forSome { type T has a Numeric[T] instance in scope }) = {
  val n= implicitly[...] // obtain the Numeric instance for x
  n.negate(x) // and use it with x
}

In words: I need a type class instance for my input argument, but I don't care about the argument's type, I just need to obtain the instance and use it on my argument.

It doesn't have to be an existential type, but I need to avoid type parameters in the def's signature.

Edit: just to clarify, the standard approach in these cases, i.e.:

def foo[T: Numeric](x: T) = ...

doesn't work for me, as it requires the addition of a type parameter on the method.

Thanks.

ncreep
  • 473
  • 3
  • 11
  • 2
    Why can't you add type parameter? – ghik Jun 30 '13 at 08:53
  • Because it would be a second type parameter in the method, which I don't want to expose to the user. And because it's second it cannot be inferred without inferring the first, but in my case the first cannot be inferred in principle. And because the whole thing is happening around macros, I cannot use something along the lines of: http://stackoverflow.com/a/10734268/1274237 as macros cannot be partially applied. – ncreep Jun 30 '13 at 08:59
  • There is no second type parameter. That expands to `def foo[T](x: T)(implicit num: Numeric[T]) = ...`. This is one type parameter, as far as I can count. – 0__ Jun 30 '13 at 11:09
  • I meant to say, that in my actual use that would be a second parameter. – ncreep Jun 30 '13 at 11:44

2 Answers2

1

I managed to make it work like this:

implicit class InstanceWithNumeric[T](val inst: T)(implicit val n: Numeric[T])

def foo(iwn: InstanceWithNumeric[_]) {
  def genFoo[T](iwn: InstanceWithNumeric[T]) {
    println(iwn.n.negate(iwn.inst))
  }
  genFoo(iwn)
}

And now:

scala> foo(1)
-1

scala> foo(1.2)
-1.2

Not the prettiest, but seems to work.

EDIT: You can avoid defining inner function like this:

implicit class InstanceWithNumeric[T](val inst: T)(implicit val n: Numeric[T]) {
  def negate = n.negate(inst)
}

Also, if you want to make implicit conversion to InstanceWithNumeric globally visible, you can do something like this:

class InstanceWithNumeric[T](val inst: T)(implicit val n: Numeric[T])
object InstanceWithNumeric {
  implicit def apply[T: Numeric](inst: T) =
    new InstanceWithNumeric(inst)
}

If you want to understand how this works, read about so called implicit scope (this question seems to contain good explanation).

Community
  • 1
  • 1
ghik
  • 10,706
  • 1
  • 37
  • 50
  • Though I had to tighten my requirements some more, you've put me on the right track, and it works now. Thanks very much! – ncreep Jun 30 '13 at 13:37
0

Not quite sure what you are attempting, because it seems you need a type once you make the call to implicitly. Would the following work for you?

def foo(implicit x: Numeric[_]) {
   //code goes here.
}
Daniel Hinojosa
  • 972
  • 5
  • 9
  • I do have an actual use case, though it's a bit tiresome to elaborate. I do actually need the combination of argument and typeclass instance, I just don't care about the type parameter, they should only be compatible. So your solution doesn't work for me, thanks anyways. – ncreep Jun 30 '13 at 06:45
  • So I get a -1 because it's tiresome for you to elaborate, and you still had to use a type parameter? – Daniel Hinojosa Jul 01 '13 at 06:35
  • I didn't downvote you, but just to compensate the unfairness, I'll give you an upvote. Sorry for the misunderstanding. – ncreep Jul 01 '13 at 07:02
  • No problem, Apologies on my end as well for thinking it was you. Thanks ncreep. – Daniel Hinojosa Jul 01 '13 at 07:12