2011-11-25 16 views
7

以下がScalaで可能である:すなわちScalaのコンストラクタ抽象

scala> val l = List 
l: scala.collection.immutable.List.type = [email protected] 

scala> l (1, 2, 3) 
res0: List[Int] = List(1, 2, 3) 

、Scalaはより高次の多型を有します。私は次のことを行うために高次多型を使用したいと思います。

sealed abstract class A { def eval() : A } 
case class A0() extends A { ... } 
case class A1 (a : A) extends A { ... } 
case class A2 (a : A, b : A) extends A { ... } 
.... 

だから私は、コンストラクタの引数必ずしも同じ番号を取らない場合クラス、Aのサブクラス、の束を持っています。アイデアはApplyAは、最初の引数としてAのサブタイプ、および引数のリストである何かのためのコンストラクタを取るということです

case class ApplyA (c : ???, l : List [ A ]) extends A { 
    def eval() : A = { ??? } } 

:私はまた、「一般的な」ケースクラス、このような何かを持っていると思います。 evalメソッドは、可能であればコンストラクタで適切なクラスを構築し(リストの長さが正しい)、 (これは上記のListの例ではl (1, 2, 3)に相当)を返します。 の最初のコンストラクタの引数の型はどうなりますか?

これは高次の多型で可能であるはずですが、どのように動かすことができませんでした。私は高次の多形性を使わなくても、単にコンストラクタを関数にラップし、次にこれらの関数をコンストラクタの最初の引数としてApplyAに渡すだけで、これを行うことができますが、高次の多型を直接使用する方法を理解したいと思います。

答えて

9

問題は、Listの例は高次多型をまったく含まないということです。 List.applyだけパラメータの可変数を取る:

def apply(xs: A*) 

高次多型は、例えば、型パラメータとして型コンストラクタを取るメソッド、または型を伴います

いいえ、高次の多型を使用することはできません。

11

@alexey_rは、あなたのListの例が高次の多型を伴わないことは間違いありません。しかし、あなたがtype-level heavy artilleryを使用する準備ができている場合は、A{0,1,2}コンストラクタのアリティを抽象化して、あなたが求めているものに非常に近いものを得ることができます。

注意すべき最初のポイントが書かれたコンストラクタcのアリティとの間には、コンパイル時チェック可能な関係がありませんので、あなたの「一般的な」クラスはおそらく、

case class ApplyA(c : ???, l : List[A]) ... 

を実装することができない、ということですリストの長さはlです。私たちは、

import shapeless.HList._ 
import shapeless.Functions._ 

sealed abstract class A { def eval() : A } 
case class A0() extends A { def eval() = this } 
case class A1 (a : A) extends A { def eval() = this } 
case class A2 (a : A, b : A) extends A { def eval() = this } 

case class ApplyA[C, L <: HList, HF](c : C, l : L) 
    (implicit hl : FnHListerAux[C, HF], ev : HF <:< (L => A)) extends A { 
    def eval() : A = hl(c)(l) 
    } 

val a : A = A0() 

val a0 = ApplyA(A0.apply _, HNil) 
val a1 = ApplyA(A1.apply _, a :: HNil) 
val a2 = ApplyA(A2.apply _, a :: a :: HNil) 

暗黙の引数hl : FnHListerAux[C, HF]があなたのコンストラクタからの変換を提供し、単一HListの引数を持つ関数にHListListを交換し、任意のアリティと通常の関数からの変換に自分自身を助けることによって、その問題を解決することができますそれが何であっても、HListの1つの引数から関数に渡されます。暗黙の引数ev : HF <:< (L => A)は、コンストラクタ引数のHListの長さが正しい長さであることを証明しています(FWIW型ですが、この例ではほとんど関係ありません)。

関連する問題