import scalaz._
import Scalaz._
-object TSV {
- type Header = Seq[Symbol]
- type Field = String
- type Record = Map[Symbol, Field]
-
- // ---
- type Failure[ F[_], R] = String => F[R]
- type Success[A, F[_], R] = A => F[R]
-
- trait Parser[A] {
- def runParser[F[_], R](kf: Failure[F, R], ks: Success[A, F, R]): F[R]
- }
+abstract class TSVTypes {
- implicit def ParserFunctor = new Functor[Parser] {
+ implicit val ParserFunctor = new Functor[Parser] {
def map[A, B](m: Parser[A])(f: A => B) = new Parser[B] {
def runParser[F[_], R](kf: Failure[F, R], ks: Success[B, F, R]): F[R] = {
def ks_(a: A) = ks(f(a))
}
}
- implicit def ParserApplicative = new Applicative[Parser] {
+ implicit val ParserApplicative = new Applicative[Parser] {
def point[A](a: => A) = new Parser[A] {
def runParser[F[_], R](kf: Failure[F, R], ks: Success[A, F, R]): F[R]
= ks(a)
}
}
- implicit def ParserMonad = new Monad[Parser] {
+ implicit val ParserMonad = new Monad[Parser] {
def point[A](a: => A) = a.point[Parser]
def bind[A, B](m: Parser[A])(f: A => Parser[B]) = new Parser[B] {
}
}
- implicit def ParserMonadError = new MonadError[({type λ[String, α] = Parser[α]})#λ, String] {
+ implicit val ParserMonadError = new MonadError[({type λ[String, α] = Parser[α]})#λ, String] {
def point[A](a: => A) = a.point[Parser]
def bind[A, B](m: Parser[A])(f: A => Parser[B]) = m.flatMap(f)
= kf(e)
}
}
+
+ implicit def ToMonadErrorOps[A](m: Parser[A]) = new {
+ def handleError(f: String => Parser[A]): Parser[A]
+ = implicitly[MonadError[({type λ[String, α] = Parser[α]})#λ, String]].handleError(m)(f)
+ }
+
implicit def ToMonadErrorIdOps(e: String) = new {
def raiseError[A]: Parser[A]
= implicitly[MonadError[({type λ[String, α] = Parser[α]})#λ, String]].raiseError(e)
}
+ type Header = Seq[Symbol]
+
+ case class Field(value: String) {
+ def parseField[A: FromField]
+ = implicitly[FromField[A]].parseField(Field(value))
+ }
+
+ case class Record(value: Map[Symbol, Field]) {
+ def parseRecord[A: FromRecord]
+ = implicitly[FromRecord[A]].parseRecord(Record(value))
+
+ def lookup[A: FromField](name: Symbol): Parser[A]
+ = value.get(name).fold(("no field named " + name.name).raiseError[A])(_.parseField[A])
+
+ def lookup[A: FromField](name: Symbol, default: String): Parser[A]
+ = value.get(name).getOrElse(Field(default)).parseField[A]
+ }
+
+ type Failure[ F[_], R] = String => F[R]
+ type Success[A, F[_], R] = A => F[R]
+
+ trait Parser[+A] {
+ def runParser[F[_], R](kf: Failure[F, R], ks: Success[A, F, R]): F[R]
+ }
+
def runParser[A](p: Parser[A]): Either[String, A] = {
type F[R] = Either[String, R]
def left (e: String): F[A] = Left(e)
def right(x: A ): F[A] = Right(x)
return p.runParser(left, right)
}
- // ---
-
- def decode[A: FromRecord](tsv: StringLike[_]): Seq[A] = {
- val lines = tsv.split('\n').filter(!_.isEmpty)
- val header = lines.head.split('\t').map(Symbol(_))
- val body = lines.tail.map(line => (header zip line.split('\t')).toMap)
- return body.map(implicitly[FromRecord[A]].parseRecord)
- }
trait FromRecord[A] {
- def parseRecord(r: Record): A
+ def parseRecord(r: Record): Parser[A]
}
trait FromField[A] {
def parseField(f: Field): Parser[A]
}
- implicit def toFromFieldOps(f: Field) = new {
- def parseField[A: FromField]
- = implicitly[FromField[A]].parseField(f)
- }
trait ToRecord[A] {
def toRecord(a: A): Record
def toField(a: A): Field
}
+ class DecodeFailedException private(e: RuntimeException) extends RuntimeException(e) {
+ def this(msg: String) = this(new RuntimeException(msg))
+ def this(msg: String, cause: Throwable) = this(new RuntimeException(msg, cause))
+ }
+
// Option[A]
implicit def OptionFromField[A: FromField] = new FromField[Option[A]] {
def parseField(f: Field): Parser[Option[A]] = {
- if (f.isEmpty) {
- return (None : Option[A]).point[Parser]
+ if (f.value.isEmpty) {
+ return None.point[Parser]
}
else {
f.parseField[A].map { Some(_) }
}
// String
- implicit def StringFromField = new FromField[String] {
- def parseField(f: Field): Parser[String] = f.point[Parser]
+ implicit val StringFromField = new FromField[String] {
+ def parseField(f: Field): Parser[String] = f.value.point[Parser]
}
// Int
- implicit def IntFromField = new FromField[Int] {
+ implicit val IntFromField = new FromField[Int] {
def parseField(f: Field): Parser[Int] = {
try {
- f.toInt.point[Parser]
+ f.value.toInt.point[Parser]
}
catch {
case e: NumberFormatException =>
}
}
}
+
+trait TSVFunctions extends TSVTypes {
+ def decode[A: FromRecord](tsv: StringLike[_]): Seq[A] = {
+ val lines = tsv.split('\n').filter(!_.isEmpty)
+ val header = lines.head.split('\t').map(Symbol(_))
+ val records = lines.tail.map(line => Record((header zip line.split('\t').map { Field(_) }).toMap))
+ return records.map { r =>
+ runParser(r.parseRecord[A]) match {
+ case Right(a) => a
+ case Left(e) => throw new DecodeFailedException(e)
+ }
+ }
+ }
+}
+
+object TSV extends TSVTypes with TSVFunctions