這是一個很好的藉口,我尋找到Shapeless,這是我一直想在某些時候做:)
$ git clone [email protected]:milessabin/shapeless.git
...
$ cd shapeless
(1)
無形狀提供了對arity的一些抽象,特別是表示爲異構列表(HList
)。任意元素的函數可以看作FnHList
(以HList
作爲參數的函數)。
$ 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
:
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
類型的類可以見證上限的說法列表:
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。在類型級別上,這將是Length
,它是爲HList
提供的。要獲得運行時值,需要另一個類型ToInt
。
這裏是最後的功能:
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()
測試:
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
操作過載,並沒有強大的類型約束,斯卡拉不會給你的Double
版本,但由於某種原因將使用Int
版本:
scala> math.max _
res18: (Int, Int) => Int = <function2>
所以我需要間接的math.max _: ((Double, Double) => Double)
來完成這項工作。
不是說這是在具體情況下做到這一點的最佳方式,但我認爲這是一個有趣的探索。
你說'g'需要一個n元組,但是你的例子'Math.max'是一個n元函數,而不是'Function1',它需要一個元組。你應該澄清一點。 –
固定,良好的漁獲 – tba