首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >输入为可变参数函数的泛型scala函数

输入为可变参数函数的泛型scala函数
EN

Stack Overflow用户
提问于 2013-06-19 16:36:35
回答 3查看 1.1K关注 0票数 7

我想定义一个接受另一个函数g的函数f。我们要求g接受n Double (对于某些固定的n)并返回Double。函数调用f(g)应返回n的特定值。

例如,f(Math.max) = 2因为Math.sin的类型是(Double, Double) => Double,而f(Math.sin) = 1因为Math.sin的类型是Double => Double

如何使用Scala泛型定义f

我已经尝试了几种形式,但都没有成功。例如:

代码语言:javascript
运行
复制
def f[A <: Product](g: Product => Double) = {...}

这不起作用,因为我们不能在编译时提取n的值,也不能约束A只包含Double值。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-06-19 16:47:15

Spray团队创建了一个名为Magnet Pattern的模式。它能做你想要的事情

票数 7
EN

Stack Overflow用户

发布于 2013-06-19 17:59:34

这是我研究Shapeless的一个很好的借口,这是我在某些时候一直想做的事情:)

代码语言:javascript
运行
复制
$ git clone git@github.com:milessabin/shapeless.git
...
$ cd shapeless

(1)

Shapeless提供了一些基于arity的抽象,特别是表示为异构表(HList)。可以将任意大小的函数视为FnHList (以HList为参数的函数)。

代码语言:javascript
运行
复制
$ sbt shapeless-core/console
scala> import shapeless._
import shapeless._

scala> def isFunction[A](fun: A)(implicit fnh: FnHLister[A]) {}
isFunction: [A](fun: A)(implicit fnh: shapeless.FnHLister[A])Unit

scala> isFunction(math.sqrt _)

scala> isFunction(math.random _)

(2)

现在让我们要求该函数返回一个Double

代码语言:javascript
运行
复制
scala> def isFunReturningDouble[A](fun: A)(implicit fnh: FnHLister[A] { type Result = Double }) {}
isFunReturningDouble: [A](fun: A)(implicit fnh: shapeless.FnHLister[A]{type Result = Double})Unit

scala> isFunReturningDouble(math.sqrt _)

scala> isFunReturningDouble(math.signum _)
<console>:12: error: could not find implicit value for parameter fnh: shapeless.FnHLister[Int => Int]{type Result = Double}
              isFunReturningDouble(math.signum _)
                                  ^

(3)

LUBConstraint类型类可以见证参数列表的上限:

代码语言:javascript
运行
复制
scala> def isValidFun[A, B <: HList](fun: A)(implicit fnh: FnHLister[A] { type Result = Double; type Args = B }, lub: LUBConstraint[B, Double]) {}
isValidFun: [A, B <: shapeless.HList](fun: A)(implicit fnh: shapeless.FnHLister[A]{type Result = Double; type Args = B}, implicit lub: shapeless.LUBConstraint[B,Double])Unit

scala> isValidFun(math.random _)

scala> isValidFun((i: Int) => i.toDouble)
<console>:12: error: could not find implicit value for parameter lub: shapeless.LUBConstraint[B,Double]
              isValidFun((i: Int) => i.toDouble)
                        ^

(4)

现在,我们仍然需要以某种方式提取arity。在类型级别上,这将是为HList提供的Length。要获取运行时值,需要另一个类型类ToInt

这里是最后一个函数:

代码语言:javascript
运行
复制
import shapeless._

def doubleFunArity[A, B <: HList, C <: Nat](fun: A)(implicit
  fnh: FnHLister[A] { type Result = Double; type Args = B }, 
  lub: LUBConstraint[B, Double],
  len: Length[B] { type Out = C },
  res: ToInt[C]
): Int = res()

测试:

代码语言:javascript
运行
复制
scala> doubleFunArity(math.sqrt _)
res15: Int = 1

scala> doubleFunArity(math.random _)
res16: Int = 0

scala> val g: (Double, Double) => Double = math.max _
g: (Double, Double) => Double = <function2>

scala> doubleFunArity(g)
res17: Int = 2

请注意,不幸的是,许多math操作都是重载的,并且没有强类型约束,Scala不会自动为您提供Double版本,但会出于某些原因使用Int版本:

代码语言:javascript
运行
复制
scala> math.max _
res18: (Int, Int) => Int = <function2>

所以我需要间接的math.max _: ((Double, Double) => Double)来让它工作。

不是说在你的具体案例中这是最好的方法,但我认为这是一次有趣的探索。

票数 6
EN

Stack Overflow用户

发布于 2013-06-19 17:17:38

可能最简单的解决方案是使用重载作为

代码语言:javascript
运行
复制
def f(g: () => Double) = 0;
def f(g: (Double) => Double) = 1;
def f(g: (Double, Double) => Double) = 2;
def f(g: (Double, Double, Double) => Double) = 2;
// ...

println(f(Math.pow _));
println(f(Math.sin _));

(由于类型擦除,您不能在运行时检查函数参数/返回类型,所以我相信您不能创建一个完全泛型的函数来满足您的需求。)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17186573

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档