2012-11-05 7 views
9

क्या स्कैला में एक वाक्यविन्यास है जो निकालने वालों को अनुकूलन तर्क लेने की अनुमति देता है? यह उदाहरण थोड़ा सा है। मान लीजिए कि मेरे पास पूर्णांक पर एक बाइनरी खोज पेड़ है, और यदि मैं कुछ कस्टम मान द्वारा इसका मूल्य विभाजित करता हूं तो मैं वर्तमान नोड पर मिलान करना चाहता हूं। ,तर्क के साथ स्कैला निकालने वाला

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 

स्काला में मैं ऐसी ही कुछ कर सकते हैं, लेकिन नहीं मैं काफी क्या चाहते हैं:

एफ # सक्रिय पैटर्न का उपयोग करना, मैं निम्न कर सकते हैं

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) 

यह अगर बहुत अच्छा होगा मैं कर सकता:

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

लेकिन यह एक संकलन समय त्रुटि है:। '=>' की उम्मीद है, लेकिन '(' पाया

विचार?

उत्तर

0

जैसा कि मुझे पता है कि जवाब नहीं है।

मैं इस मामले के लिए पिछले तरीके का भी उपयोग करता हूं।

6

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.

और:

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

अर्थात, नहीं NodeDivisibleBy(2) की तरह एक अभिव्यक्ति।

तो नहीं, स्कैला में किसी भी सीधा तरीके से यह संभव नहीं है, और व्यक्तिगत रूप से मुझे लगता है कि यह ठीक है: निम्नलिखित लिखना है (जिस तरह से मैं शायद NodeDivisibleBy ऑब्जेक्ट और आयात में परिभाषित करता हूं):

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

एक छोटी सी कीमत मामले खंड में मनमाने ढंग से भाव को समझने के लिए नहीं होने की वृद्धि की पठनीयता के लिए भुगतान करने के लिए है।

4

ट्रैविस ब्राउन ने नोट किया है, यह स्कैला में वास्तव में संभव नहीं है।

मैं उस परिदृश्य में जो करता हूं वह सिर्फ अपघटन को एक गार्ड और उपनाम के साथ परीक्षण से अलग करता है।

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") 
} 

एक अलग DivisibleBy परिभाषित स्पष्ट रूप से इस सरल मामले में पूरा overkill है, लेकिन एक समान तरीके से और अधिक जटिल स्थितियों में पठनीयता मदद मिल सकती है एफ # सक्रिय पैटर्न करते हैं।

तुम भी नोड की विधि के रूप divisibleBy निर्धारित कर सकते हैं और है:

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") 
} 

जो मुझे लगता है कि अधिक पठनीय है (यदि अधिक शब्द) एफ # संस्करण

2

बाइंड एक साथ मामले वर्ग, विधेय से और तर्क, फिर परिणाम के रूप में सामान्य रूप से मैच।

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

यह स्काला 2.10 सही है? –

संबंधित मुद्दे