2016-06-23 10 views
1

def parse[T <: HList](list: List[String]): Validation[T]を書きたいと思います。 listList("fooid", "barid")TFooId :: BarId :: HNilParse[T]String => Validation[FooId]を実装するtypeclassとすることができます。どのようにしてparseと書いたら、リストをTに解析しますか? Tの各要素の暗黙的な型式を呼び出す方法がわかりません。リストをHListに解析する

答えて

2

shapeless.ops.traversable.FromTraversableからコードを適合させることができます。

私はあなたのValidationタイプが何であるかわからないんだけど、私は(主にので、私は簡単に私にいくつかのParseインスタンスを与えることstring構文を使用することができます)以下scalaz.ValidationNel[String, A]のエイリアスとしてそれを使用。 Parser型クラスは、ソートして

import scalaz.{Validation => _, _}, Scalaz._ 

type Validation[A] = ValidationNel[String, A] 

trait Parse[T] { 
    def apply(s: String): Validation[T] 
} 

object Parse { 
    def fromScalazParse[E <: Exception, T](f: String => scalaz.Validation[E, T]) = 
    new Parse[T] { 
     def apply(s: String): Validation[T] = 
     f(s).leftMap(_.getMessage).toValidationNel 
    } 

    implicit val booleanParse = fromScalazParse(_.parseBoolean) 
    implicit val intParse  = fromScalazParse(_.parseInt) 
    implicit val doubleParse = fromScalazParse(_.parseDouble) 
} 

、我々は今List[String]を解析し、私たちに与えることをFromTraversableに基づいて型クラスを作成することができValidation[A :: B :: HNil]:私たちはFromTraversableParsedを使用して作るために、いくつかの構文を追加することができます

import shapeless._ 
import scala.collection.GenTraversable 

trait FromTraversableParsed[Out <: HList] extends Serializable { 
    def apply(l: GenTraversable[String]) : Validation[Out] 
} 

object FromTraversableParsed { 
    def apply[Out <: HList](implicit from: FromTraversableParsed[Out]) = from 

    implicit val hnilFromTraversableParsed = 
    new FromTraversableParsed[HNil] { 
     def apply(l: GenTraversable[String]): Validation[HNil] = 
     if(l.isEmpty) HNil.successNel[String] 
     else "Traversable is not empty".failureNel[HNil] 
    } 

    implicit def hlistFromTraversableParsed[OutH, OutT <: HList](implicit 
    ftpT: FromTraversableParsed[OutT], 
    parseH: Parse[OutH] 
): FromTraversableParsed[OutH :: OutT] = 
    new FromTraversableParsed[OutH :: OutT] { 
     def apply(l : GenTraversable[String]) : Validation[OutH :: OutT] = 
     if(l.isEmpty) "Empty traversable".failureNel[OutH :: OutT] 
     else (parseH(l.head) |@| ftpT(l.tail))(_ :: _) 
    } 
} 

もう少し簡単にできます:

implicit class ParseStringListOps(val strings: List[String]) extends AnyVal { 
    def parse[L <: HList](implicit ftp: FromTraversableParsed[L]): Validation[L] = 
    ftp(strings) 
} 

今すぐできる:

List("1", "true", "3.0").parse[Int :: Boolean :: Double :: HNil] 
// Validation[Int :: Boolean :: Double :: HNil] = Success(1 :: true :: 3.0 :: HNil) 
+0

ありがとうございます。 gitterチャンネルでは、https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/ops/hlists.scala#L2815について言及しましたが、それを使用することは可能でしょうか?自分のTCを書くのをスキップしますか? – Reactormonk

+0

私は 'LiftAll'はParse [Int] :: Parse [Boolean] :: Parse [Double] :: HNil'を与えることができると思いますが、これを使って' List [String] '? –

+0

'List [String] => String :: String :: String :: HNil'の行に沿って何かを見つけ出し、' LiftAll'の 'HList'を使ってそれを詰め、それを検証してトラバースします。 – Reactormonk

関連する問題