1

私はこれをタイプセーフな方法で機能させようとしています:

val rows = db.select( ID_COLUMN, STR("name"), INT("count") ). from("tablename") ......
for ( (id, name, count) <- rows ) {
       //some code to use the individual values
}

これまでのところ、シェイプレス以外にこれをタイプセーフにする別の方法は見つかりませんでした。

私は slick やその他の ORM について知っています。

HList は、異種のオブジェクトの束を渡し、特定の型の値のリストを取得する方法のようです。

私はこのようなことをしようとしました:

 trait ColDef [X] {
     def colName
     def valalue (m:Map[String, Object]):X
 }

 object XS extends ColDef[String]{
     def colName = "s"
     def value (m:Map[String, Object]) = m("s").asInstanceOf[String] 
 }

 object XI extends ColDef[Integer]{
     def colName = "i"
     def value (m:Map[String, Object]) = m("i").asInstanceOf[Integer] 
 }

 val xhl = XS::XI::HNil
 val data:Map[String,Object] = Map(("s" ->"asdf"), ("i" -> new Integer(5)))

 object p1 extends Poly1 {
    implicit def getValue[T, S <% ColDef[T]] = at[S] (coldef => coldef.value(data) )
 }

 val res = xhl map p1 
 val (s, i) = res.tupled //this works, giving s:String, and i:Integer

 //but following does not compile
 def nextstep(hl : HList, data:Map[String,Object]) = {
     hl map p1
 }

重要なことを繰り返します。

HList/Shapeless は問題を解決するための候補となる可能性がありますが、この演習の目標ではありません。私の目標は、関数の戻り値の型を、渡された変数の型とパラメーターの数に対応させることです。

私の小さなユーティリティのユーザーが HList について知る必要がなければ理想的ですが、それは実際の要件ではありません。

重要な部分は、結果のタイプを params のタイプと一致させることです。

val param1 = new Conf[String]
val param2 = new Conf[Integer]
 ... etc ....
val res = function(param1, param2, param3) 

より正確には、上記のパラメータのペイロード タイプです。つまり、 res のタイプは T(String, Integer, ....) になります。


別の説明を追加させてください。任意のアリティのメソッドを作成し、パラメーターの数ごとに関数を作成することを避けたいと考えています。22 個のメソッドで問題がなければ、次のようになります。

def f[A](a:ColDef[A]):(A)
def f[A,B](a:ColDef[A], b:ColDef[B]):(A,B)
def f[A,B,C](a:ColDef[A], b:ColDef[B],c:ColDef[C]):(A,B,C)
 ..... and so on

そして、可能なすべてのタプルが明示的に定義されるため、 shapeless または HList は必要ありません。

これら 3 つの署名を実際に見てみましょう - それらを 22 にするのは少し時間がかかりますが、形のない依存関係を回避し、実装もワンライナーになります。30 分かけて手動で (または小さなスクリプトを使用して) 実行する必要があるかもしれません。

4

1 に答える 1

1

HList の入力と出力で動作させる

の定義に若干の調整が必要なだけですnextstep

def nextstep[L <: HList](hl: L, data: Map[String, Object])(implicit mapper: Mapper[p1.type, L]): mapper.Out = {
  hl map p1
}

HList の正確な型をL型引数にし、暗黙的に必要な by を要求しましたmap(mapの定義を参照)。

次に、あなた(またはあなたのユーザー)は単に呼び出すことができます

nextstep(XS :: XI :: HNil, data)

String :: Integer :: HNil戻り値の型として取得されます。(結果の HList を返す)の任意の HList に対して期待どおりに機能しColDef[...]ます。

タプルを入力 (および出力 HList) として動作させる

HList の代わりにタプルを返すようにするには、次のように定義します。

import shapeless.ops.hlist.{Tupler, Mapper}
def nextstep[L <: HList, OutL <: HList, Out](hl: L, data: Map[String, Object])(implicit mapper: Mapper.Aux[p1.type, L, OutL], tupler: Tupler.Aux[OutL, Out]): Out = {
  tupler(hl map p1)
}

nextstep(XS :: XI :: HNil, data)を返し(String, Integer)nextstep一般的なケースでは正しく型付けされたタプルを返します。

入力および出力としてのタプル

ColDefのタプルを入力として受け入れ、タプルを出力として返す最後のステップは次のようになります。

def nextstep[P, L <: HList, OutL <: HList, Out](c: P, data: Map[String, Object])(implicit gen: Generic.Aux[P, L], mapper: Mapper.Aux[p1.type, L, OutL], tupler: Tupler.Aux[OutL, Out]): Out = {
  tupler(gen.to(c) map p1)
}

ここでのロジックは、 で定義されている関数と非常によく似ていますshapeless.syntax.std.TupleOps。つまり、タプルを HList に変換し、HList を処理して、出力をタプルに変換します。

于 2014-07-19T19:23:21.953 に答える