]> gitweb @ CieloNegro.org - task-reporter.git/blob - src/main/scala/jp/ymir/taskReporter/core/TSV.scala
monadic tsv
[task-reporter.git] / src / main / scala / jp / ymir / taskReporter / core / TSV.scala
1 package jp.ymir.taskReporter.core
2 import scala.collection._
3 import scala.collection.immutable.StringLike
4 import scala.language.higherKinds
5 import scalaz._
6
7 object TSV {
8   type Header = Seq[Symbol]
9   type Field  = String
10   type Record = Map[Symbol, Field]
11
12   // ---
13   type Failure[   F[_], R] = String => F[R]
14   type Success[A, F[_], R] = A      => F[R]
15
16   trait Parser[A] {
17     def runParser[F[_], R](kf: Failure[F, R], ks: Success[A, F, R]): F[R]
18   }
19
20   implicit def ParserFunctor = new Functor[Parser] {
21     def map[A, B](m: Parser[A])(f: A => B) = new Parser[B] {
22       def runParser[F[_], R](kf: Failure[F, R], ks: Success[B, F, R]): F[R] = {
23         def ks_(a: A) = ks(f(a))
24         return m.runParser(kf, ks_)
25       }
26     }
27   }
28
29   implicit def ParserApplicative = new Applicative[Parser] {
30     def point[A](a: => A) = new Parser[A] {
31       def runParser[F[_], R](kf: Failure[F, R], ks: Success[A, F, R]): F[R] = ks(a)
32     }
33
34     def ap[A, B](m: => Parser[A])(fm: => Parser[A => B]) = new Parser[B] {
35       def runParser[F[_], R](kf: Failure[F, R], ks: Success[B, F, R]): F[R] = {
36         def ks_(f: A => B): F[R] = {
37           def ks__(a: A) = ks(f(a))
38           return m.runParser(kf, ks__)
39         }
40         return fm.runParser(kf, ks_)
41       }
42     }
43   }
44
45   implicit def ParserMonad = new Monad[Parser] {
46     def point[A](a: => A) = implicitly[Applicative[Parser]].point(a)
47
48     def bind[A, B](m: Parser[A])(f: A => Parser[B]) = new Parser[B] {
49       def runParser[F[_], R](kf: Failure[F, R], ks: Success[B, F, R]): F[R] = {
50         def ks_(a: A) = f(a).runParser(kf, ks)
51         return m.runParser(kf, ks_)
52       }
53     }
54   }
55
56   def runParser[A](p: Parser[A]): Either[String, A] = {
57     type F[A] = Either[String, A]
58     def left (errMsg: String): F[A] = Left(errMsg)
59     def right(x     : A     ): F[A] = Right(x)
60     return p.runParser(left, right)
61   }
62   // ---
63
64   def decode[A: FromRecord](tsv: StringLike[_]): Seq[A] = {
65     val lines  = tsv.split('\n').filter(!_.isEmpty)
66     val header = lines.head.split('\t').map(Symbol(_))
67     val body   = lines.tail.map(line => (header zip line.split('\t')).toMap)
68     return body.map(implicitly[FromRecord[A]].parseRecord)
69   }
70
71   trait FromRecord[A] {
72     def parseRecord(r: Record): A
73   }
74
75   trait FromField[A] {
76     def parseField(f: Field): A
77   }
78   def parseField[A: FromField](f: Field): A
79     = implicitly[FromField[A]].parseField(f)
80
81   trait ToRecord[A] {
82     def toRecord(a: A): Record
83   }
84
85   trait ToField[A] {
86     def toField(a: A): Field
87   }
88
89   // Option[A]
90   implicit def OptionFromField[A: FromField] = new FromField[Option[A]] {
91     def parseField(f: Field): Option[A] = {
92       if (f.isEmpty) {
93         return None
94       }
95       else {
96         return Some(implicitly[FromField[A]].parseField(f))
97       }
98     }
99   }
100
101   // String
102   implicit def StringFromField = new FromField[String] {
103     def parseField(f: Field): String = f
104   }
105
106   // Int
107   implicit def IntFromField = new FromField[Int] {
108     def parseField(f: Field): Int = f.toInt
109   }
110 }