2012-11-05 26 views
9

Có cú pháp nào trong Scala cho phép trình giải nén có một đối số tùy chỉnh không? Ví dụ này là một chút contrived. Giả sử tôi có một cây tìm kiếm nhị phân trên các số nguyên và tôi muốn khớp trên nút hiện tại nếu giá trị của nó có thể chia hết cho một số giá trị tùy chỉnh.Scala Extractor với đối số

Sử dụng F # mô hình hoạt động, tôi có thể làm như sau:

type Tree = 
    | Node of int * Tree * Tree 
    | Empty 

let (|NodeDivisibleBy|_|) x t = 
    match t with 
    | Empty -> None 
    | Node(y, l, r) -> if y % x = 0 then Some((l, r)) else None 

let doit = function 
    | NodeDivisibleBy(2)(l, r) -> printfn "Matched two: %A %A" l r 
    | NodeDivisibleBy(3)(l, r) -> printfn "Matched three: %A %A" l r 
    | _ -> printfn "Nada" 

[<EntryPoint>] 
let main args = 
    let t10 = Node(10, Node(1, Empty, Empty), Empty) 
    let t15 = Node(15, Node(1, Empty, Empty), Empty) 

    doit t10 
    doit t15 

    0 

Trong Scala, tôi có thể làm điều gì đó tương tự, nhưng không hoàn toàn những gì tôi muốn:

sealed trait Tree 
case object Empty extends Tree 
case class Node(v: Int, l: Tree, r: Tree) extends Tree 

object NodeDivisibleBy { 
    def apply(x: Int) = new { 
    def unapply(t: Tree) = t match { 
     case Empty => None 
     case Node(y, l, r) => if (y % x == 0) Some((l, r)) else None 
    } 
    } 
} 

def doit(t: Tree) { 
    // I would prefer to not need these two lines. 
    val NodeDivisibleBy2 = NodeDivisibleBy(2) 
    val NodeDivisibleBy3 = NodeDivisibleBy(3) 
    t match { 
    case NodeDivisibleBy2(l, r) => println("Matched two: " + l + " " + r) 
    case NodeDivisibleBy3(l, r) => println("Matched three: " + l + " " + r) 
    case _ => println("Nada") 
    } 
} 

val t10 = Node(10, Node(1, Empty, Empty), Empty) 
val t15 = Node(15, Node(1, Empty, Empty), Empty) 

doit(t10) 
doit(t15) 

Nó sẽ là tuyệt vời nếu Tôi có thể làm:

case NodeDivisibleBy(2)(l, r) => println("Matched two: " + l + " " + r) 
case NodeDivisibleBy(3)(l, r) => println("Matched three: " + l + " " + r) 

nhưng đây là lỗi thời gian biên dịch: '=>' mong đợi nhưng '(' tìm thấy.

Suy nghĩ?

Trả lời

0

Như tôi biết câu trả lời là không.

Tôi cũng sử dụng cách trước cho trường hợp này.

6

Từ the spec:

SimplePattern ::= StableId ‘(’ [Patterns] ‘)’ 

An extractor pattern x(p1, ..., pn) where n ≥ 0 is of the same syntactic form as a constructor pattern. However, instead of a case class, the stable identifier x denotes an object which has a member method named unapply or unapplySeq that matches the pattern.

và:

A stable identifier is a path which ends in an identifier.

nghĩa là, không phải là một biểu hiện như NodeDivisibleBy(2). Vì vậy, không, điều này là không thể trong bất kỳ cách đơn giản trong Scala, và cá nhân tôi nghĩ rằng đó là tốt: phải viết sau (mà theo cách tôi có thể xác định trong đối tượng NodeDivisibleBy và nhập khẩu):

val NodeDivisibleBy2 = NodeDivisibleBy(2) 
val NodeDivisibleBy3 = NodeDivisibleBy(3) 

là một mức giá nhỏ để trả cho khả năng đọc không cần giải mã các biểu thức tùy ý trong mệnh đề trường hợp.

4

Như Travis Brown đã lưu ý, nó không thực sự có thể trong scala.

Việc tôi làm trong trường hợp đó chỉ là tách phân tách khỏi thử nghiệm với một người bảo vệ và bí danh.

val DivisibleBy = (n: Node, x: Int) => (n.v % x == 0) 

def doit(t: Tree) = t match { 
    case n @ Node(y, l, r) if DivisibleBy(n,2) => println("Matched two: " + l + " " + r) 
    case n @ Node(y, l, r) if DivisibleBy(n,3) => println("Matched three: " + l + " " + r) 
    case _ => println("Nada") 
} 

Xác định một riêng biệt DivisibleBy rõ ràng là quá mức cần thiết hoàn toàn trong trường hợp đơn giản này, nhưng có thể giúp dễ đọc trong kịch bản phức tạp hơn trong một cách tương tự như F # mô hình tích cực làm.

Bạn cũng có thể xác định divisibleBy như một phương pháp của Node và có:

case class Node(v: Int, l: Tree, r: Tree) extends Tree { 
    def divisibleBy(o:Int) = (v % o)==0 
} 

def doit(t: Tree) = t match { 
    case n @ Node(y, l, r) if n divisibleBy 2 => println("Matched two: " + l + " " + r) 
    case n @ Node(y, l, r) if n divisibleBy 3 => println("Matched three: " + l + " " + r) 
    case _ => println("Nada") 
} 

mà tôi nghĩ là dễ đọc hơn (nếu tiết hơn) so với F # phiên bản

2

Bind cùng lớp trường hợp, vị ngữ và đối số, sau đó khớp với kết quả như bình thường.

case class Foo(i: Int) 

class Testable(val f: Foo, val ds: List[Int]) 

object Testable { 
    def apply(f: Foo, ds: List[Int]) = new Testable(f, ds) 
    def unapply(t: Testable): Option[(Foo, List[Int])] = { 
    val xs = t.ds filter (t.f.i % _ == 0) 
    if (xs.nonEmpty) Some((t.f, xs)) else None 
    } 
} 

object Test extends App { 
    val f = Foo(100) 

    Testable(f, List(3,5,20)) match { 
    case Testable(f, 3 :: Nil) => println(s"$f matched three") 
    case Testable(Foo(i), 5 :: Nil) if i < 50 
           => println(s"$f matched five") 
    case Testable(f, ds)  => println(s"$f matched ${ds mkString ","}") 
    case _      => println("Nothing") 
    } 
} 
+0

Đây là Scala 2.10 phải không? –

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