2012-03-07 37 views
11

Tôi đã viết một số trình phân tích cú pháp từ thư viện kết hợp. Tôi muốn một hàm tổng quát biến đổi bất kỳ kích cỡ tổ nào thành một danh sách. Làm như thế nào ?Scala: Làm phẳng phân tích cú pháp (~) từ trình kết hợp bộ phân tích cú pháp thành Danh sách?

Dưới đây là ví dụ về trình phân tích cú pháp tôi sử dụng (trình phân tích cú pháp thực của tôi có chuỗi rất dài ~ vì vậy tôi muốn tránh giải pháp hiện tại của tôi có nhận xét dưới đây).

object CombinatorParser extends RegexParsers { 

    lazy val a = "a" 
    lazy val b = "b" 
    lazy val c = "c" 
    lazy val content = a ~ b ~ c // ^^ {case a~b => a::b::c::Nil work but I want something more general that work for any ~ length. 
} 

object CombinatorTesting { 

    def main(args:Array[String]) { 
    val testChar = "abc" 
    val output = CombinatorParser.parseAll(CombinatorParser.content, testChar) 
    println(output) // ((a~b)~c) but I want List(a,b,c) 
    } 
} 
+0

Tôi không nghĩ đó là có thể. Bạn không thể tách dây chuyền thành những miếng nhỏ hơn? Chính xác những gì bạn đang cố gắng để làm? Có lẽ nếu bạn cho thêm một chút ngữ cảnh, ai đó có một giải pháp tốt hơn cho việc này. – drexin

Trả lời

19

Đây là một ứng dụng tốt (và khá đơn giản) cho loại kỹ thuật lập trình chung được minh họa trong shapeless.

Với định nghĩa của bạn,

object CombinatorParser extends RegexParsers { 
    lazy val a = "a" 
    lazy val b = "b" 
    lazy val c = "c" 
    lazy val content = a ~ b ~ c 
} 

Chúng đệ quy có thể định nghĩa một lớp kiểu đó sẽ san bằng kết quả của nó như sau,

import CombinatorParser._ 

Đầu tiên chúng ta định nghĩa một đặc điểm mà (trừu tượng) flattens một trận đấu tùy ý M đến một List[String],

trait Flatten[M] extends (M => List[String]) { 
    def apply(m : M) : List[String] 
} 

T hen chúng tôi cung cấp trường lớp kiểu cho tất cả các hình dạng của M mà chúng ta đang quan tâm: trong trường hợp này, String, A ~ BParseResult[T] (nơi A, BT là tất cả các loại mà có Flatten trường hợp),

// 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 
} 

Cuối cùng chúng ta có thể định nghĩa một hàm tiện để đơn giản hóa việc áp dụng Flatten trường hợp để phân tích kết quả,

def flatten[P](p : P)(implicit flatten : Flatten[P]) = flatten(p) 

Và bây giờ chúng tôi đã sẵn sàng để đ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) 
6

Nếu bạn muốn có một giải pháp mà không lập trình generic ...

def flatten(res: Any): List[String] = res match { 
    case x ~ y => flatten(x) ::: flatten(y) 
    case None => Nil 
    case Some(x) => flatten(x) 
    case x:String => List(x) 
    } 

    val testChar = "abc" 
    val output = CombinatorParser.parseAll(CombinatorParser.content, testChar).getOrElse(None) 
    println(flatten(output)) 
+0

Cảm ơn bạn đã đơn giản. Nó chỉ hoạt động. – JulienD

Các vấn đề liên quan