我按照here找到的建议来定义一个名为square的函数,然后尝试将它传递给一个名为square的函数。函数定义如下:
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))
当调用两次(square,2)时,REPL会发出错误消息:
scala> twice(square, 2)
<console>:8: error: could not find implicit value for parameter numeric: Numeric[T]
twice(square, 2)
^
任何?
答案 0 :(得分:21)
除了Andrew Phillips之外,我不同意这里的所有人。好吧,到目前为止每个人。 :-)问题出在这里:
def twice[T](f: (T) => T, a: T): T = f(f(a))
您希望,像Scala的新手经常这样做,Scala的编译器会将两个参数都考虑到twice
以推断出正确的类型。但是,Scala并没有这样做 - 它只使用从一个参数列表到下一个参数列表的信息,而不是从一个参数到下一个参数。这意味着参数f
和a
是独立分析的,而不具备知道对方是什么的优势。
这意味着,例如,此有效:
twice(square[Int], 2)
现在,如果你将它分解为两个参数列表,那么它也可以工作:
def twice[T](a: T)(f: (T) => T): T = f(f(a))
twice(2)(square)
所以,基本上,你要做的一切都是正确的,应该可以正常工作,除了之外你想要一个参数的部分来帮助找出另一个参数的类型(就像你写的那样) )。
答案 1 :(得分:4)
这是来自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
显然,在隐式可以解决之前,需要知道“两次(3)”的类型。我想这是有道理的,但如果斯卡拉大师可以评论这一点,我仍然会很高兴......
答案 2 :(得分:1)
另一种解决方案是将方块提升为部分应用的功能:
scala> twice(square(_:Int),2)
res1: Int = 16
这样,隐式应用于square,如:
scala> twice(square(_:Int)(implicitly[Numeric[Int]]),2)
res3: Int = 16
还有另一种方法:
def twice[T:Numeric](f: (T) => T, a: T): T = f(f(a))
scala> twice[Int](square,2)
res1: Int = 16
但同样,类型参数不会被推断。
答案 3 :(得分:1)
你的问题是 square 不是一个函数(即scala.Function1 [T,T] aka(T)=&gt; T)。相反,它是一个带有多个参数列表的类型参数化方法,其中一个是隐式的...... Scala中没有语法来定义完全等效的函数。
有趣的是,你对Numeric类型类的使用意味着Scala中排名较高的函数的常用编码并不直接适用于此,但是我们可以根据这种情况调整它们并得到类似的结果,
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)
}
这为我们提供了一个排名较高的“函数”,其类型参数是上下文绑定到Numeric,
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")
我们现在可以根据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
这种方法的明显缺点是你会失去Scala单态函数文字的简洁性。