Scala - 如何在使用之前排除我的函数的泛型类型?

Cor*_* Wu 1 generics scala implicit typeclass

我有地图的String,以FunctionS的所有细节的是在语言的有效功能.当我向地图添加一个函数时,我需要指定类型(在本例中Int).

var functionMap: Map[String, (Nothing) => Any] = Map[String, (Nothing) => Any]()

functionMap += ("Neg" -> expr_neg[Int])

def expr_neg[T: Numeric](value: T)(implicit n: Numeric[T]): T = {
  n.negate(value)
} 
Run Code Online (Sandbox Code Playgroud)

相反,我该怎么做:

functionMap += ("Neg" -> expr_neg)
Run Code Online (Sandbox Code Playgroud)

没有,[Int]并在我打电话后添加它:

(unaryFunctionMap.get("abs").get)[Int](-45)
Run Code Online (Sandbox Code Playgroud)

Dan*_*etz 5

您正在尝试使用类型类(在本例中Numeric)构建函数.类型类依赖于隐式参数.隐含在编译时解决.您的函数名称字符串值仅在运行时已知,因此您不应在类似类之上构建解决方案.

另一种方法是在地图中为每个参数类型存储单独的函数对象.您可以使用以下内容存储参数类型TypeTag:

import scala.reflect.runtime.universe._

var functionMap: Map[(String, TypeTag[_]), (Nothing) => Any] = Map()

def addFn[T: TypeTag](name: String, f: T => Any) =
  functionMap += ((name, typeTag[T]) -> f)

def callFn[T: TypeTag](name: String, value: T): Any =
  functionMap((name, typeTag[T])).asInstanceOf[T => Any](value)

addFn[Int]("Neg", expr_neg)
addFn[Long]("Neg", expr_neg)
addFn[Double]("Neg", expr_neg)

val neg10 = callFn("Neg", 10)
Run Code Online (Sandbox Code Playgroud)

没有类型类隐式需要解析才能调用callFn(),因为隐式Numeric调用已经解析了addFn.


如果我们在调用函数时尝试解析类型类会发生什么?

第一个问题是a Function1(或Function2)不能有隐式参数.只有一种方法可以.(有关更多解释,请参阅此其他问题.)因此,如果您想要一些行为类似Function1但采用隐式参数的东西,则需要创建自己的类型来定义apply()方法.但它必须是一种不同的类型Function1.

现在我们解决了主要问题:所有implicits都必须能够在编译时解决.在运行方法的代码中的位置,需要选择隐式值所需的所有类型信息.在以下代码示例中:

unaryFunctionMap("abs")(-45)
Run Code Online (Sandbox Code Playgroud)

我们并不需要指定我们的值类型Int,因为它可以从值-45本身推断出来.但是我们的方法使用Numeric隐式值的事实无法从该行代码中的任何内容推断出来.我们需要Numeric在编译时指定某处的使用.

如果您可以为带有数值的一元函数创建单独的映射,则(相对)容易:

trait UnaryNumericFn {
  def apply[T](value: T)(implicit n: Numeric[T]): Any
}

var unaryNumericFnMap: Map[String, UnaryNumericFn] = Map()

object expr_neg extends UnaryNumericFn {
  override def apply[T](value: T)(implicit n: Numeric[T]): T = n.negate(value)
}

unaryNumericFnMap += ("Neg" -> expr_neg)

val neg3 = unaryNumericFnMap("Neg")(3)
Run Code Online (Sandbox Code Playgroud)

你可以在它需要的类型类上使函数trait泛型,让你的map包含使用不同类型类的一元函数.这需要在内部进行强制转换,并将规范移动Numeric到最终调用函数的位置:

trait UnaryFn[-E[X]] {
  def apply[T](value: T)(implicit ev: E[T]): Any
}

object expr_neg extends UnaryFn[Numeric] {
  override def apply[T](value: T)(implicit n: Numeric[T]): T = n.negate(value)
}

var privateMap: Map[String, UnaryFn[Nothing]] = Map()

def putUnary[E[X]](key: String, value: UnaryFn[E]): Unit =
  privateMap += (key -> value)

def getUnary[E[X]](key: String): UnaryFn[E] =
  privateMap(key).asInstanceOf[UnaryFn[E]]

putUnary("Neg", expr_neg)

val pos5 = getUnary[Numeric]("Neg")(-5)
Run Code Online (Sandbox Code Playgroud)

但你还是要指定Numeric某个地方.

此外,这些方法都无法解决,因为写的,支持函数的并不需要类型类.被强制要明确哪些函数采用隐式参数,以及它们使用什么类型的含义,首先就会破坏使用含义的目的.