Jest to dobry (i dość prosty) wniosek o rodzaju ogólnych technik programowania wskazanym w shapeless.
Biorąc swoją definicję,
object CombinatorParser extends RegexParsers {
lazy val a = "a"
lazy val b = "b"
lazy val c = "c"
lazy val content = a ~ b ~ c
}
Możemy rekurencyjnie określić klasę typu, który będzie go wyprostować za wyniki w następujący sposób,
import CombinatorParser._
najpierw zdefiniować cechy, które (abstrakcyjnie) spłaszcza dowolny mecz M
do List[String]
,
trait Flatten[M] extends (M => List[String]) {
def apply(m : M) : List[String]
}
T kura zapewniamy instancje klasy typu dla wszystkich kształtów M
które Cię interesują: w tym przypadku, String
, A ~ B
i ParseResult[T]
(gdzie A
, B
i T
są wszystkie typy, dla których istnieją Flatten
przypadki),
// Flatten instance for String
implicit def flattenString = new Flatten[String] {
def apply(m : String) = List(m)
}
// Flatten instance for `A ~ B`. Requires Flatten instances for `A` and `B`.
implicit def flattenPattern[A, B]
(implicit flattenA : Flatten[A], flattenB : Flatten[B]) =
new Flatten[A ~ B] {
def apply(m : A ~ B) = m match {
case a ~ b => flattenA(a) ::: flattenB(b)
}
}
// Flatten instance for ParseResult[T]. Requires a Flatten instance for T.
implicit def flattenParseResult[T]
(implicit flattenT : Flatten[T]) = new Flatten[ParseResult[T]] {
def apply(p : ParseResult[T]) = (p map flattenT) getOrElse Nil
}
Wreszcie możemy zdefiniować funkcję wygoda w celu uproszczenia stosowania Flatten
instancji do analizowania wyników,
def flatten[P](p : P)(implicit flatten : Flatten[P]) = flatten(p)
a teraz jesteśmy gotowi iść,
val testChar = "abc"
val output = parseAll(content, testChar)
println(output) // ((a~b)~c) but I want List(a, b, c)
val flattenedOutput = flatten(output)
println(flattenedOutput) // List(a, b, c)
Nie sądzę, że to możliwe. Nie możesz podzielić swoich łańcuchów na mniejsze kawałki? Co dokładnie próbujesz zrobić? Może jeśli podasz trochę więcej kontekstu, ktoś ma lepsze rozwiązanie. – drexin