をこれは、私は常にいくつかの時点でやってみたかった何か私はShapelessに見するための良い口実だった:)
$ git clone [email protected]:milessabin/shapeless.git
...
$ cd shapeless
を
(1)
シェイプレスは、アリティに対していくつかの抽象化、特に異種リスト(HList
)としての表現を提供します。任意のアリティの関数は、FnHList
(引数としてHList
をとる関数)と見ることができます。
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
型クラスは、引数の上限を目撃することができます
$ 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 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)
ここでも何らかの形でアリティを抽出する必要があります。タイプレベルでは、これはのために提供されるLength
です。ランタイム値を取得するには、別のタイプのクラス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()
テスト:残念ながら、多くのmath
操作が過負荷、および強力な型制約なしている
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
注、ScalaはあなたにDouble
を与えることはありませんバージョンは自動的に使用されますが、何らかの理由でInt
バージョンが使用されます:
scala> math.max _
res18: (Int, Int) => Int = <function2>
この作業を行うには、間接指示math.max _: ((Double, Double) => Double)
が必要です。
具体的なケースでこれを行うのが最良の方法だとは言えませんが、私はそれが楽しい探索だったと思います。
あなたは、 'g'はnタプルを取ると言っていますが、あなたの例である' Math.max'はタプルを取る 'Function1'ではなく、n項関数です。あなたはそれを明確にすべきです。 –
固定式、良好なキャッチ – tba