2008-11-02 15 views
37

मैं वर्तमान में ओकैमल के साथ एक छोटी परियोजना पर काम कर रहा हूं; एक साधारण गणितीय अभिव्यक्ति सरलीकृत। मुझे अभिव्यक्ति के अंदर कुछ पैटर्न मिलना चाहिए, और उन्हें सरल बनाना ताकि अभिव्यक्ति के अंदर कोष्ठक की संख्या कम हो। अब तक मैं दो को छोड़कर अधिकांश नियमों को लागू करने में सक्षम हूं, जिसके लिए मैंने एक पुनरावर्ती, पैटर्न-मिलान "फ़िल्टर" फ़ंक्शन बनाने का निर्णय लिया है। दो नियम मैं लागू करने के लिए की जरूरत है:ओकैमल: किसी अन्य के अंदर मिलान अभिव्यक्ति?

-Turn सभी प्रपत्र एक की अभिव्यक्ति - (ब + स) या इसी तरह के एक - बी - सी

-Turn प्रपत्र एक/(ख के सभी भाव * सी) या एक/बी/सी

... जैसा कि मुझे संदेह है कि काफी सरल होगा, और एक बार जब मैं एक को लागू करने में कामयाब रहा हूं, तो मैं अन्य को आसानी से कार्यान्वित कर सकता हूं। हालांकि, मुझे रिकर्सिव पैटर्न-मिलान फ़ंक्शन के साथ समस्या हो रही है। मेरी टाइप अभिव्यक्ति यह है:

type expr = 
| Var of string   (* variable *) 
| Sum of expr * expr  (* sum *) 
| Diff of expr * expr  (* difference *) 
| Prod of expr * expr  (* product *) 
| Quot of expr * expr  (* quotient *) 
;; 

और जो मुख्य रूप से मुझे परेशानी हो रही है, वह मिलान अभिव्यक्ति में है। उदाहरण के लिए, मैं कुछ इस तरह कोशिश कर रहा हूँ:

let rec filter exp = 
    match exp with  
    | Var v -> Var v       
    | Sum(e1, e2) -> Sum(e1, e2)   
    | Prod(e1, e2) -> Prod(e1, e2) 
    | Diff(e1, e2) -> 
     match e2 with 
     | Sum(e3, e4) -> filter (diffRule e2) 
     | Diff(e3, e4) -> filter (diffRule e2)  
     | _ -> filter e2   
    | Quot(e1, e2) ->         ***this line*** 
     match e2 with 
     | Quot(e3, e4) -> filter (quotRule e2)   
     | Prod(e3, e4) -> filter (quotRule e2)   
     | _ -> filter e2 
;; 

हालांकि, ऐसा लगता है कि चिह्नित लाइन पर मैच अभिव्यक्ति "प्रिंसिपल मैच" के बजाय पिछले "आंतरिक मैच" का हिस्सा होने के रूप में पहचाना जा रहा है , इसलिए सभी "कोट (...)" अभिव्यक्ति कभी पहचानी नहीं जाती हैं। क्या इस तरह के अन्य मैच एक्सप्रेशन के अंदर मैच एक्सप्रेशन होना भी संभव है? और आंतरिक मिलान को समाप्त करने का सही तरीका क्या होगा ताकि मैं अन्य संभावनाओं से मेल खाना जारी रख सकूं?

तर्क को अनदेखा करें, क्योंकि यह बहुत पहले से आया है, यह सिर्फ इतना है कि मैं इसे आजमाने में सक्षम नहीं हूं क्योंकि मुझे पहले इस "मैच" त्रुटि से निपटना है, हालांकि इस पर कोई सिफारिश पुनरावृत्ति या तर्क को संभालने का स्वागत किया जाएगा।

उत्तर

58

त्वरित समाधान

तुम बस कोष्ठकों जोड़ने की जरूरत है, या begin/end, भीतरी मैच के चारों ओर:

let rec filter exp = 
    match exp with 
    | Var v -> Var v 
    | Sum (e1, e2) -> Sum (e1, e2) 
    | Prod (e1, e2) -> Prod (e1, e2) 
    | Diff (e1, e2) -> 
      (match e2 with 
      | Sum (e3, e4) -> filter (diffRule e2) 
      | Diff (e3, e4) -> filter (diffRule e2) 
      | _ -> filter e2) 
    | Quot (e1, e2) -> 
      (match e2 with 
      | Quot (e3, e4) -> filter (quotRule e2) 
      | Prod (e3, e4) -> filter (quotRule e2) 
      | _ -> filter e2) 
;; 

सरलीकरण

अपने विशेष मामले में कोई एक घोंसला मैच की जरूरत है। आप केवल बड़े पैटर्न का उपयोग कर सकते हैं। तुम भी "|" ("या") पैटर्न का उपयोग नेस्टेड नियमों में डुप्लिकेशन समाप्त कर सकते हैं:

let rec filter exp = 
    match exp with 
    | Var v -> Var v 
    | Sum (e1, e2) -> Sum (e1, e2) 
    | Prod (e1, e2) -> Prod (e1, e2) 
    | Diff (e1, (Sum (e3, e4) | Diff (e3, e4) as e2)) -> filter (diffRule e2) 
    | Diff (e1, e2) -> filter e2 
    | Quot (e1, (Quot (e3, e4) | Prod (e3, e4) as e2)) -> filter (quotRule e2) 
    | Quot (e1, e2) -> filter e2 
;; 

आप _ (अंडरस्कोर) के साथ अप्रयुक्त पैटर्न चर की जगह तो यह और भी अधिक पठनीय बना सकते हैं। यह भी इस तरह के (e3,e4) टपल रूप में पूरे उप पैटर्न के लिए काम करता है:

let rec filter exp = 
    match exp with 
    | Var v -> Var v 
    | Sum (e1, e2) -> Sum (e1, e2) 
    | Prod (e1, e2) -> Prod (e1, e2) 
    | Diff (_, (Sum _ | Diff _ as e2)) -> filter (diffRule e2) 
    | Diff (_, e2) -> filter e2 
    | Quot (_, (Quot _ | Prod _ as e2)) -> filter (quotRule e2) 
    | Quot (_, e2) -> filter e2 
;; 

उसी तरह, आप सरल बनाने आगे बढ़ सकते हैं।उदाहरण के लिए, पहले तीन मामलों में (Var, Sum, Prod) असंशोधित लौटा दिए जाते हैं, जो आप सीधे व्यक्त कर सकते हैं:

let rec filter exp = 
    match exp with 
    | Var _ | Sum _ | Prod _ as e -> e 
    | Diff (_, (Sum _ | Diff _ as e2)) -> filter (diffRule e2) 
    | Diff (_, e2) -> filter e2 
    | Quot (_, (Quot _ | Prod _ as e2)) -> filter (quotRule e2) 
    | Quot (_, e2) -> filter e2 
;; 

अंत में, आप function शॉर्टकट के साथ e द्वारा e2 की जगह और जगह ले सकता है match:

let rec filter = function 
    | Var _ | Sum _ | Prod _ as e -> e 
    | Diff (_, (Sum _ | Diff _ as e)) -> filter (diffRule e) 
    | Diff (_, e) -> filter e 
    | Quot (_, (Quot _ | Prod _ as e)) -> filter (quotRule e) 
    | Quot (_, e) -> filter e 
;; 

ओकैमल का पैटर्न वाक्यविन्यास अच्छा है, है ना?

11

आप अंडरस्कोर, जैसे और या पैटर्न के न्यायसंगत उपयोग के द्वारा इस terser (और मैं स्पष्ट तर्क दूंगा) कर सकते हैं। परिणामी कोड भी अधिक कुशल है, क्योंकि यह कम आवंटित करता है (Var, Sum और Prod मामलों में)

let rec filter = function 
| Var _ | Sum _ | Prod _ as e -> e 
| Diff (_, (Sum _ | Diff _) as e) -> filter (diffRule e) 
| Diff (_,e) -> e 
| Quot (_, (Quot _| Prod _) as e) -> filter (quoteRule e) 
| Quot (_,e) -> filter e 
;; 
+0

यह समाधान अमान्य है। * त्रुटि: कन्स्ट्रक्टर डिफ 2 तर्क (ओं) की अपेक्षा करता है, लेकिन यहां 1 तर्क (ओं) पर लागू होता है * – vog

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