Function transfer for all applicable types

I followed the advice found here to define a function called square, and then tried to pass it to a function called twice. Functions are defined as follows:

def square[T](n: T)(implicit numeric: Numeric[T]): T = numeric.times(n, n) def twice[T](f: (T) => T, a: T): T = f(f(a)) 

When called twice (square, 2) REPL gives an error message:

 scala> twice(square, 2) <console>:8: error: could not find implicit value for parameter numeric: Numeric[T] twice(square, 2) ^ 

Is anyone

+5
source share
4 answers

I disagree with everyone here except Andrew Phillips . Well, everything is still. :-) The problem is here:

 def twice[T](f: (T) => T, a: T): T = f(f(a)) 

You expect that, like newcomers to Scala, they often do, for the Scala compiler to consider both parameters up to twice to output the correct types. Scala does not do this, however - it uses information from only one parameter list for the next, but not from one parameter to another. This means that the parameters f and a analyzed independently, without any advantage, knowing what is different.

This means, for example, that this works:

 twice(square[Int], 2) 

Now, if you split it into two parameter lists, then it also works:

 def twice[T](a: T)(f: (T) => T): T = f(f(a)) twice(2)(square) 

So basically, everything you tried to do was correct and should work, except for the part that you expected from one parameter to help figure out the type of another parameter (as you wrote it).

+20
source

Here's a session from Scala REPL.

 Welcome to Scala version 2.8.0.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_20). Type in expressions to have them evaluated. Type :help for more information. scala> def square[T : Numeric](n: T) = implicitly[Numeric[T]].times(n, n) square: [T](n: T)(implicit evidence$1: Numeric[T])T scala> def twice2[T](f: T => T)(a: T) = f(f(a)) twice2: [T](f: (T) => T)(a: T)T scala> twice2(square)(3) <console>:8: error: could not find implicit value for evidence parameter of type Numeric[T] twice2(square)(3) ^ scala> def twice3[T](a: T, f: T => T) = f(f(a)) twice3: [T](a: T,f: (T) => T)T scala> twice3(3, square) <console>:8: error: could not find implicit value for evidence parameter of type Numeric[T] twice3(3, square) scala> def twice[T](a: T)(f: T => T) = f(f(a)) twice: [T](a: T)(f: (T) => T)T scala> twice(3)(square) res0: Int = 81 

Thus, it is obvious that the type “twice (3)” must be known before the implicit can be resolved. I think it makes sense, but I would still be happy if the Scala guru could comment on this ...

+4
source

Another solution is to raise the square by a partially applied function:

 scala> twice(square(_:Int),2) res1: Int = 16 

Thus, implicit is applied to the square, as in:

 scala> twice(square(_:Int)(implicitly[Numeric[Int]]),2) res3: Int = 16 

There is another approach:

 def twice[T:Numeric](f: (T) => T, a: T): T = f(f(a)) scala> twice[Int](square,2) res1: Int = 16 

But again, the type parameter is not output.

+1
source

Your problem is that the square is not a function (i.e. a scala.Function1 [T, T] aka (T) => T). Instead, it is a type parameterized method with several lists of arguments, one of which is implicit ... there is no syntax in Scala to define an exactly equivalent function.

Interestingly, using the Numeric Type class means that the usual encodings of high-level functions in Scala are not directly applied here, but we can adapt them to this case and get something like this,

 trait HigherRankedNumericFunction { def apply[T : Numeric](t : T) : T } val square = new HigherRankedNumericFunction { def apply[T : Numeric](t : T) : T = implicitly[Numeric[T]].times(t, t) } 

This gives us a higher level “function” with its type parameter limited to the “Numeric” parameter,

 scala> square(2) res0: Int = 4 scala> square(2.0) res1: Double = 4.0 scala> square("foo") <console>:8: error: could not find implicit value for evidence parameter of type Numeric[java.lang.String] square("foo") 

Now we can define twice in terms of HigherRankedNumericFunctions,

 def twice[T : Numeric](f : HigherRankedNumericFunction, a : T) : T = f(f(a)) scala> twice(square, 2) res2: Int = 16 scala> twice(square, 2.0) res3: Double = 16.0 

The obvious drawback of this approach is that you lose the literal multiplicity of the Scala monomorphic function.

+1
source

All Articles