より多くの型情報が必要であるということは普通で、値はHList
静的型の場合は、アプローチを変更する必要があります。基本的にHList
で何もできないのは、それがHList
(それに値を追加する以外に)だと知っていれば、通常はタイプ制限としてHList
と書いてあります。
あなたの場合は、タイプアライメントされたシーケンスの一種です。このアプローチで前進する前に、実際にあなたが実際に必要としていることを本当に確かめることをお勧めします。機能(とConversion
のような機能のようなタイプ)についての良い点の1つは、A => B
とB => C
があり、A => C
にそれらを合成して、B
を永遠に忘れることができるということです。あなたはきれいなクリーンなブラックボックスを手に入れることができます。
しかし、場合によっては、パイプラインの部分を反映できるような方法で機能的なものを構成できることが有用な場合もあります。私はこれがこれらのケースの1つであると仮定しようとしていますが、それはあなた自身で確認する必要があります。そうでなければ、あなたは運がいい、何が来るかはまあまあです。
私はこれらの型を仮定します:
import shapeless._
trait TypeAligned[L <: HList] extends DepFn1[L] {
type I <: Convertable
type O <: Convertable
type Out = Conversion[I, O]
}
L
:
trait Convertable
trait Conversion[A <: Convertable, B <: Convertable] {
def convert(a: A): B
}
我々は、特定のHList
は、その種類に並ぶ一回の以上の変換で構成されている証人という型クラスを定義することができますパイプラインに関するすべてのタイプ情報を含み、I
およびO
がそのエンドポイントのタイプです。
次の私たちは、このタイプのクラスのインスタンス(これはcompanionedされる2つのための上記の特性と一緒に定義されなければならないことに注意してください)必要があります。
object TypeAligned {
type Aux[L <: HList, A <: Convertable, B <: Convertable] = TypeAligned[L] {
type I = A
type O = B
}
implicit def firstTypeAligned[
A <: Convertable,
B <: Convertable
]: TypeAligned.Aux[Conversion[A, B] :: HNil, A, B] =
new TypeAligned[Conversion[A, B] :: HNil] {
type I = A
type O = B
def apply(l: Conversion[A, B] :: HNil): Conversion[A, B] = l.head
}
implicit def composedTypeAligned[
A <: Convertable,
B <: Convertable,
C <: Convertable,
T <: HList
](implicit
tta: TypeAligned.Aux[T, B, C]
): TypeAligned.Aux[Conversion[A, B] :: T, A, C] =
new TypeAligned[Conversion[A, B] :: T] {
type I = A
type O = C
def apply(l: Conversion[A, B] :: T): Conversion[A, C] =
new Conversion[A, C] {
def convert(a: A): C = tta(l.tail).convert(l.head.convert(a))
}
}
}
そして今、あなたのAutoConversion
のバージョンを書くことができますがパイプラインについての型情報のすべてを追跡します:
class AutoConversion[L <: HList, A <: Convertable, B <: Convertable](
path: L
)(implicit ta: TypeAligned.Aux[L, A, B]) extends Conversion[A, B] {
def convert(a: A): B = ta(path).convert(a)
}
そして、あなたはこのようにそれを使用することができます:
case class AutoA(i: Int) extends Convertable
case class AutoB(s: String) extends Convertable
case class AutoC(c: Char) extends Convertable
val ab: Conversion[AutoA, AutoB] = new Conversion[AutoA, AutoB] {
def convert(a: AutoA): AutoB = AutoB(a.i.toString)
}
val bc: Conversion[AutoB, AutoC] = new Conversion[AutoB, AutoC] {
def convert(b: AutoB): AutoC = AutoC(b.s.lift(3).getOrElse('-'))
}
val conv = new AutoConversion(ab :: bc :: HNil)
およびconv
は、予想される静的タイプ(およびConversion[AutoA, AutoC]
を実装)を持ちます。