2010-09-01 12 views
7

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

नोट:test विशेष रूप से क्या मैं की बात कर रहा हूँ।

type State = { input:string; index:int; succeeded:bool } 
type Matcher = State -> State 

let term (cs:char Set) = 
    fun s -> 
     if s.succeeded && s.index < s.input.Length && cs.Contains s.input.[s.index] then 
      { input = s.input; index = s.index + 1; succeeded = true } 
     else 
      { input = s.input; index = s.index; succeeded = false } 

let quantify (term, min, max) = 
    let rec inner (s:State, count) = 
     if s.succeeded && s.index < s.input.Length && count <= max then 
      inner (term { input = s.input; index = s.index + 1; succeeded = true }, count + 1) 
     elif count >= min && count <= max then 
      { input = s.input; index = s.index - 1; succeeded = true }  
     else 
      s   
    fun s -> inner (s, 0) 

let disjunction leftTerm rightTerm = 
    fun s -> 
     let left = leftTerm s 
     if not left.succeeded then 
      let right = rightTerm s 
      if not right.succeeded then 
       { input = s.input; index = s.index; succeeded = false } 
      else 
       right 
     else 
      left 

let matcher input terms = 
    let r = terms { input = input; index = 0; succeeded = true } 
    if r.succeeded then r.input.Substring (0, r.index) else null 

let test = // (abc|xyz)a{2,3}bc 
    disjunction // (abc|xyz) 
     (term (set "a") >> term (set "b") >> term (set "c")) 
     (term (set "x") >> term (set "y") >> term (set "z")) 
    >> quantify (term (set "a"), 2, 3) // (a{2,3}) 
    >> term (set "b") // b 
    >> term (set "c") // c 

let main() : unit = 
    printfn "%s" (matcher "xyzaabc" test) 
    System.Console.ReadKey true |> ignore 

main() 

उत्तर

8

कोड मेरे लिए बहुत अच्छा लग रहा है।

मुझे यकीन नहीं है कि यह आपका इरादा या संयोग था, लेकिन आप "पार्सर संयोजक" के समान कुछ लागू कर रहे हैं, जो कई अकादमिक कागजात का विषय है :-)। मुझे लगता है कि Monadic Parser Combinators काफी पठनीय है (इसमें हास्केल में उदाहरण हैं, लेकिन आप उन्हें एफ # में अनुवाद करने में सक्षम होना चाहिए)।

फ़ंक्शन संरचना ऑपरेटर के संबंध में। मैं आम तौर पर ऑपरेटर का उपयोग करने का एक बड़ा प्रशंसक नहीं हूं, क्योंकि यह अक्सर कोड को खराब करता है। हालांकि, आपके उदाहरण में यह एक अच्छी समझ में आता है क्योंकि आप आसानी से कल्पना कर सकते हैं कि >> का अर्थ है "इस समूह का उस समूह द्वारा पालन किया जाना चाहिए", जो व्याख्या करना आसान है।

// Test against several terms in sequence 
let sequence terms = (fun state -> terms |> Seq.fold (>>) state) 
// Test for a substring 
let substring s = sequence [ for c in s -> term (set [c]) ] 

let test = // (abc|xyz)a{2,3}bc 
    (substring "abc" <|> substring "xyz") 
    >> quantify 2 3 (term (set "a")) // (a{2,3}) 
    >> substring "bc" // bc 

यह अधिक है:

केवल मामूली परिवर्तन है कि मैं क्या करना होगा, ताकि आप उदाहरण इस बात के लिए लिख सकते हैं disjunction ऑपरेशन के लिए कुछ अच्छा कस्टम ऑपरेटर चुन सकते हैं और कुछ और आदिम संचालन परिभाषित करने के लिए, है उच्च स्तरीय विवरण, इसलिए यह >> ऑपरेटर को उन कार्यों के पक्ष में हटा देता है जो अधिक वर्णनात्मक हैं (और >> encapsulate)। मैं भी quantify बदल एक ट्रिपल के बजाय कई तर्क लेने के लिए

आप आगे इस के साथ खेलने के लिए चाहते हैं, तो आप लेख पर एक नज़र डालें और एफ # गणना अभिव्यक्ति बिल्डर लिखने की कोशिश कर सकते हैं (जो एक मामूली परिवर्तन है) कि आपको parser { .. } वाक्यविन्यास का उपयोग करने की अनुमति देगा।

+1

यह जानना अच्छा है कि मैं अपने कार्यात्मक प्रोग्रामिंग कौशल में प्रगति कर रहा हूं। आपने मुझे सुरुचिपूर्ण कम्प्यूटेशनल अभिव्यक्ति वाक्यविन्यास में सभी के साथ प्रयास करने और लपेटने के लिए वास्तव में उत्साहित किया है। :) वैसे भी आपकी सलाह और पेपर * के लिए धन्यवाद * (मैं एरिक मीजर का कुछ प्रशंसक हूं।) *। – ChaosPandion

+0

दिलचस्प पेपर; लिंक पोस्ट करने के लिए धन्यवाद। – TechNeilogy

3

यह आम तौर पर अच्छी शैली है लेकिन आप कुछ चालें खो रहे हैं और अभी भी बहुत कम रिडंडेंसी है। हो सकता है कि इस तरह से अधिक:

let valid (s: State) = s.succeeded && s.index < s.input.Length 
... 
let disjunction leftTerm rightTerm s = 
    let left = leftTerm s 
    if left.succeeded then left else 
    let right = rightTerm s 
    if right.succeeded then right else 
     { s with succeeded = false } 
... 
let test = 
    let f s = set s |> term 
    let (++) s t = f s >> f t 
    disjunction ("a" ++ "b" ++ "c") ("x" ++ "y" ++ "z") 
    >> quantify (f "a", 2, 3) 
    >> "b" ++ "c" 

आप बंद के बजाय एक गणना का प्रतिनिधित्व करने, क्योंकि यह बहुत आसान बना देता है डिबगिंग एक मूल्य जमा करने के लिए पसंद कर सकते हैं।

+0

वाह मैं उस वैध 'फ़ंक्शन' के साथ आने के लिए मूर्खतापूर्ण महसूस नहीं करता हूं। आपके सुझावों के लिए धन्यवाद। – ChaosPandion

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