2009-05-07 12 views
16

कभी-कभी मैं अभी भी प्रक्रियात्मक कोड को कार्यात्मक कोड में अनुवाद करने की कोशिश कर रहा हूं।प्रक्रियात्मक प्रोग्रामर के लिए कार्यात्मक कोड स्निपेट की सूची?

क्या कार्यात्मक मुहावरे/स्निपेट्स की मैप किए गए कार्यात्मक मुहावरे/स्निपेट की एक सूची है?

संपादित

चूंकि इन स्निपेट की एक केंद्रीकृत वेबसाइट होना प्रतीत नहीं होता है, मैं एक समुदाय विकि में इस मोड़ कर रहा हूँ। कृपया किसी भी प्रक्रियात्मक -> कार्यात्मक स्निपेट पेस्ट करें।

+3

शायद समुदाय विकी होना चाहिए - कोई "उत्तर" प्रति से नहीं होना चाहिए? – Anthony

+0

@ एंथनी, मुझे उम्मीद है कि एक वेबसाइट है, लेकिन अगर ऐसा नहीं है, तो मैं इसे बनाउंगा। – Unknown

+1

ऐसा लगता है कि आपने इस समुदाय को बहुत जल्द बनाया है - कृपया देखें pleac-ocaml – Thelema

उत्तर

9

पहली बार मैं/तोड़ने के लिए तक पहुँचने के लिए OCaml/एफ # जारी रखने के लिए चला गया, यह मुझे एक के लिए फेंक दिया (अनंत (fshub पर this post से संपादित)) लूप, तो बोलने के लिए, क्योंकि ऐसी कोई चीज मौजूद नहीं है! ओकैमल में, कोई लूप से तोड़ने के लिए अपवादों का उपयोग कर सकता है क्योंकि वे बहुत सस्ते हैं, लेकिन F # (में।नेट) ओवरहेड काफी सामान्य है और "सामान्य" प्रवाह नियंत्रण के लिए उपयोगी नहीं है।

यह थोड़ी देर पहले (कुछ समय मारने के लिए) सॉर्ट एल्गोरिदम के साथ खेलते समय आया, जो दोहराने/तब तक टूटने का भारी उपयोग करता है। यह मुझे मारा कि रिकर्सिव पूंछ कॉल फ़ंक्शन एक ही परिणाम प्राप्त कर सकते हैं, केवल पठनीयता के लिए थोड़ी सी डिंग के साथ। इसलिए, मैंने 'म्यूटेबल बीडोन' और 'बीडीओएन नहीं' को फेंक दिया और इन अनिवार्य संरचनाओं के बिना कोड लिखने की कोशिश की। निम्नलिखित लूपिंग भागों को दूर करता है और दिखाता है कि दोहराना/कब तक, लिखना/कब, करना/करना, ब्रेक/जारी रखना, और टेलीक-इन-द-मिडिल स्टाइल कोड टेलकॉल का उपयोग करके लिखना है। ये सभी परंपरागत एफ # 'जबकि' कथन के समान गति से चलने लगते हैं, लेकिन आपका माइलेज भिन्न हो सकता है (कुछ प्लेटफॉर्म ठीक से टेलिकॉल को लागू नहीं कर सकते हैं और इसलिए जब तक वे पैच नहीं किए जाते हैं तो गलती हो सकती है)। अंत में तुलना के लिए, दोनों शैलियों में लिखे गए एक (खराब) सॉर्ट एल्गोरिदम है।

चलो परंपरागत एफ # अनिवार्य शैली में लिखे गए 'डू/एंड' लूप के साथ शुरू करते हैं, फिर कार्यात्मक विविधताएं देखें जो समान प्रकार के लूप दोनों के साथ-साथ विभिन्न अर्थशास्त्र जैसे/करते हैं, दोहराना/जब तक, बीच में परीक्षण करें, और यहां तक ​​कि तोड़ें/जारी रखें (मोनैड के बिना .. उम, वर्कफ़्लोज़!)।

#light 
(* something to work on... *) 
let v = ref 0 
let f() = incr v; 
let g() = !v; 
let N = 100000000 

let imperDoWhile() = 
    let mutable x = 0 
    let mutable bDone = false 
    while not bDone do 
     f() 
     x <- x + 1 
     if x >= N then bDone <- true 

ठीक है, यह काफी आसान है। ध्यान रखें कि एफ() को कम से कम एक बार (कब/करते समय) कहा जाता है।

यहां एक ही कोड है, लेकिन एक कार्यात्मक शैली में। ध्यान दें कि हमें यहां एक म्यूटेबल घोषित करने की आवश्यकता नहीं है।

let funDoWhile() = 
    let rec loop x = 
     f()    (*Do*) 
     if x < N then (*While*) 
      loop (x+1) 
    loop 0 

हम किसी ब्लॉक के अंदर फ़ंक्शन कॉल डालकर परंपरागत/समय के दौरान इसे स्पिन कर सकते हैं।

let funWhileDo() = 
    let rec loop x = 
     if x < N then (*While*) 
      f()   (*Do*) 
      loop (x+1) 
    loop 0 

कुछ स्थिति सत्य होने तक ब्लॉक को दोहराने के बारे में (दोहराना/कब तक)? काफी आसान ...

let funRepeatUntil() = 
    let rec loop x = 
     f()     (*Repeat*) 
     if x >= N then() (*Until*) 
     else loop (x+1) 
    loop 0 

मोनाड-कम ब्रेक के बारे में क्या था? खैर, बस एक सशर्त अभिव्यक्ति प्रस्तुत करें जो 'यूनिट' लौटाती है, जैसे:

let funBreak() = 
    let rec loop() = 
     let x = g() 
     if x > N then() (*break*) 
     else 
      f() 
      loop() 
    loop() 

जारी रखने के बारे में कैसे? खैर, यह सिर्फ लूप के लिए एक और कॉल है! सबसे पहले, एक वाक्य रचना बैसाखी के साथ:

let funBreakContinue() = 
    let break'() =() 
    let rec continue'() = 
     let x = g() 
     if x > N then break'() 
     elif x % 2 = 0 then 
      f(); f(); f(); 
      continue'() 
     else 
      f() 
      continue'() 
    continue'() 

और फिर फिर से (बदसूरत) वाक्य रचना बैसाखी के बिना:

let funBreakContinue'() = 
    let rec loop() = 
     let x = g() 
     if x > N then() 
     elif x % 2 = 0 then 
      f(); f(); f(); 
      loop() 
     else 
      f() 
      loop() 
    loop() 

आसान पाई के रूप में!

इन लूप रूपों का एक अच्छा परिणाम यह है कि यह आपके लूप में राज्यों को स्पॉट और कार्यान्वित करना आसान बनाता है। उदाहरण के लिए, एक बुलबुला सॉर्ट लगातार एक संपूर्ण सरणी पर लूप करता है, जो मूल्यों से बाहर हो जाता है, जैसा कि उन्हें पाता है। यह ट्रैक करता है कि सरणी पर एक पास किसी एक्सचेंज का उत्पादन करता है या नहीं। यदि नहीं, तो प्रत्येक मान सही जगह पर होना चाहिए, इसलिए क्रम समाप्त हो सकता है। एक अनुकूलन के रूप में, सरणी के माध्यम से प्रत्येक पास पर, सरणी में अंतिम मान सही स्थान पर क्रमबद्ध होता है। तो, लूप को हर बार एक से छोटा किया जा सकता है। अधिकांश एल्गोरिदम एक स्वैप की जांच करते हैं और हर बार एक "bmodified" ध्वज अपडेट करते हैं। हालांकि, एक बार पहला स्वैप पूरा हो जाने के बाद, उस असाइनमेंट की कोई आवश्यकता नहीं है; यह पहले से ही सच है!

यहां एफ # कोड है जो एक बबल सॉर्ट लागू करता है (हाँ, बबल सॉर्ट भयानक एल्गोरिदम है; क्विकसॉर्ट चट्टानों)। अंत में एक अनिवार्य कार्यान्वयन है जो राज्य को नहीं बदलता है; यह प्रत्येक एक्सचेंज के लिए bmodified ध्वज अद्यतन करता है।दिलचस्प बात यह है कि अनिवार्य समाधान छोटे सरणी पर तेज़ है और बड़े पैमाने पर केवल एक प्रतिशत या दो धीमी है। (हालांकि, एक अच्छा उदाहरण के लिए बनाया गया)।

let inline sort2 f i j (a:'a array) = 
    let i' = a.[ i ] 
    let j' = a.[ j ] 
    if f i' j' > 0 then 
     a.[ i ] <- j' 
     a.[ j ] <- i' 

let bubble f (xs:'a array) = 
    if xs.Length = 0 
    then() 

    let rec modified i endix = 
     if i = endix then 
      unmodified 0 (endix-1) 
     else 
      let j = i+1 
      sort2 f i j xs 
      modified j endix 
    and unmodified i endix = 
     if i = endix then 
      () 
     else 
      let j = i+1 
      let i' = xs.[ i ] 
      let j' = xs.[ j ] 
      if f i' j' > 0 then 
       xs.[ i ] <- j' 
       xs.[ j ] <- i' 
       modified j endix 
      else 
       unmodified j endix 
    in unmodified 0 (xs.Length-1) 

let bubble_imperitive f (xs:'a array) = 
    let mutable bModified = true 
    let mutable endix = xs.Length - 1 
    while bModified do 
     bModified <- false 
     endix <- endix - 1 
     for i in 0..endix do 
      let j = i+1 
      let i' = xs.[ i ] 
      let j' = xs.[ j ] 
      if f i' j' > 0 then 
       xs.[ i ] <- j' 
       xs.[ j ] <- i' 
       bModified <- true 
     done 
    done 
+0

युक्तियों के लिए धन्यवाद पूंछ रिकर्सन लागू करने पर। [मुझे बहुत मदद मिली] (http://codereview.stackexchange.com/questions/59314/refactoring-while-do-array-comparison-function-into-tail-recursion-with-f)। =) –

4

ओह, अब यह निफ्टी प्रश्न है। यहाँ कुछ, code snips in python या कुछ cloe हैं:

  • छोरों के लिए iterators

    stripped_list = [line.strip() for line in line_list]

  • छोरों के लिए

    साथ प्रतिस्थापित किया जा सकता है के साथ बदला जा सकता है लागू होते हैं या नक्शा या फ़िल्टर कर

    मानचित्र (ऊपरी, ['वाक्य', 'खंड']) [ 'वाक्य', 'FRAGMENT']

  • छोरों के स्थान पर कार्यों

  • पूंछ प्रत्यावर्तन की संरचना के साथ छोरों के लिए नेस्ट

  • के स्थान पर जनरेटर भाव के लिए लूप

    sum(x*x for x in range(10))

+0

स्निप नंबर दो को 'नक्शा (str.upper, ...' शुरू करना चाहिए क्योंकि ऊपरी वर्ग str की एक विधि है: str.upper। –

2

पुरानी होमवर्क प्रश्न:

समारोह

(define f-imperative (y) (x) ; x is a local variable 
    (begin 
    (set x e) 
    (while (p x y) 
     (set x (g x y))) 
    (h x y))) 

असाइनमेंट और पाशन के साथ एक विशिष्ट जरूरी शैली में है। समकक्ष फ़ंक्शन एफ-फ़ंक्शनल लिखें जो अनिवार्य सुविधाओं का उपयोग नहीं करता है (अनुक्रमित), जबकि (गोटो), और सेट (असाइनमेंट)। आप जितनी चाहें उतनी '' सहायक कार्य '' का उपयोग कर सकते हैं, जब तक कि उन्हें चलो या लेट्रेक का उपयोग करके परिभाषित किया गया हो और शीर्ष स्तर पर नहीं।

एक समाधान:

; The idea is simple: 
; Use parameter passing for binding the values 
; of the variables and recursion instead of iteration. 
; 
; For those who like theory this is the main argument for proving 
; that recursive functions (LISP, lambda calculus) have the same 
; computational power as any imperative programming language. 

(define f-functional (y) 
    (letrec (
    (f-helper (lambda (x y) 
        (if (p x y) 
        (f-helper (g x y) y) 
        (h x y))))) 
    (f-helper e y))) 

; Notice that y in f-helper is invariant. Therefore, we can rewrite 
; f-helper without y as follows. 

(define f-functional (y) 
    (letrec (
    (f-helper (lambda (x) 
        (if (p x y) 
        (f-helper (g x y)) 
        (h x y))))) 
    (f-helper e))) 

; This is not the only solution, though I think it is one of the 
; nicer ones. 
2

गुना एक बहुत ही रोचक कार्य है, जो कई कार्यात्मक एल्गोरिदम में केंद्रीय है। मान लीजिए कि हम एक सूची के सभी तत्व जोड़ना चाहते हैं। प्रक्रियात्मक कोड में, आप आम तौर पर एक संचयक चर बनाते हैं और इसे 0 पर सेट करते हैं, फिर सूची के माध्यम से पुनरावृत्त करते हैं और आइटम द्वारा संचयक को बढ़ाते हैं।

OCaml में, आप गुना का उपयोग करके एक कार्यात्मक तरह से समान कार्य:

List.fold_left (+) 0 [1; 2; 3];; 
- : int = 6 

गुना का उपयोग करके आप उदाहरण के लिए सूची में शब्दों की संख्या की गणना और उन्हें एक ही समय में जोड़ सकते हैं:

List.fold_left (fun (count, concat) e -> (count + 1, concat^e)) (0, "") ["a"; "b"; "c"];; 
- : int * string = (3, "abc") 

गुना का एक और उपयोगी उपयोग एक वेक्टर को एक सेट में कॉपी करना है। चूंकि ओकैम में सेट अपरिवर्तनीय हैं, इसलिए आपको प्रभावी रूप से सूची के प्रत्येक आइटम को एक नया सेट बनाने की आवश्यकता है जिसमें पिछले सेट और नया आइटम शामिल है।

module Int = struct type t = int let compare = compare end;; 
module IntSet = Set.Make(Int);; 

let s = List.fold_left (fun set e -> IntSet.add e set) IntSet.empty [1; 2; 3];; 
val s : IntSet.t = <abstr> 

IntSet.elements s;; 
- : IntSet.elt list = [1; 2; 3] 

यहाँ, हमारी प्रारंभिक वस्तु एक खाली सेट है, और प्रत्येक कॉल पर, एक नया सेट, बनाई गई है पिछले सेट और IntSet.add का उपयोग करके वर्तमान आइटम पर आधारित है।

हुड के तहत यह कैसे किया जाता है, यह जानने के लिए एक बार फिर से फोल्ड लागू करें, फिर हर जगह अंतर्निहित संस्करण का उपयोग करें। यहां तक ​​कि C12+ में, std::accumulate के साथ!

2

पीएलईएसी प्रोजेक्ट लगभग अपने लक्ष्य के रूप में लगभग है - अन्य भाषाओं में पर्ल कुकबुक में सभी उदाहरणों को लागू करें। ओकैम संस्करण (जो तीन 100% पूर्ण में से एक है) के लिंक यहां दिए गए हैं http://pleac.sourceforge.net/pleac_ocaml/index.html

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