2015-02-14 8 views
8

ओकैमल में, अगर मुझे कई का उपयोग करके एक फ़ंक्शन लिखना है, तो बाकी, नीचे मेरा बेवकूफ और बदसूरत समाधान है।ओसीएमएल में कोड के बाद बहुत बहुस्तरीय नेस्टेड लिखें?

let foo() = 
    let a1 = ... in 
    if (a1) then 
    result1 
    else 
    let a2 = ... in 
    if (a2) then 
     result2 
    else 
     let a3 = ... in 
     if (a3) then 
     result3 
     else 
     let a4 = ... in 
     if (a4) then 
      result4 
     else 
      result5. 

ऊपर दिए गए कोड को कैसे सुशोभित करें? मुझे सी/सी ++ & जावा शैली पसंद है जो अगली if-statement के इंडेंटेशन को सहेजने के लिए "वापसी" का उपयोग करती है। क्या मैं ओकैमल के साथ एक ही काम कर सकता हूं?

int foo() = { 
    bool a1 = ...; 
    if (a1) 
    return result1; 

    bool a2 = ...; 
    if (a2) 
    return result2; 

    bool a3 = ...; 
    if (a3) 
    return result3; 

    bool a4 = ...; 
    if (a4) 
    return result4; 

    return result5; 
} 
+1

OCaml एक 'return' बयान नहीं है:' if' शायद जाने के लिए रास्ता है। यदि आप बेताब हो जाते हैं तो आप चीजों को किसी अन्य कार्य में विभाजित कर सकते हैं। – gsg

+0

सीढ़ी में अपना पहला उदाहरण इंडेंट करने का कोई कारण नहीं है। कई संपादक इसे लंबवत रूप से इंडेंट करेंगे –

+0

ओकैम में कुछ मोनैड लाइब्रेरी कुछ 'रिटर्न' फ़ंक्शन को परिभाषित करते हैं –

उत्तर

3

if वाक्यात्मक निर्माणों वास्तव में सी और OCaml में एक ही तरह से काम नहीं करते। सी, if सिंटैक्स फॉर्म ओकैम में वे अभिव्यक्ति हैं। सी से OCamlif?: टर्नरी ऑपरेटर में सबसे नज़दीक मिलता है। यदि आप if के बजाय इस ऑपरेटर का उपयोग करके अपने सी कोड को फिर से लिखने का प्रयास करते हैं, तो आपको एक ही चुनौती का सामना करना पड़ेगा। इसका मतलब यह नहीं है कि यह असंभव है, क्योंकि अन्य उत्तरों आपको समाधान देते हैं।

let rec foo() = 
    let a1 = … (* computation *) in 
    if a1 
    then result1 
    else foo2() 
and foo2() = 
    let a2 = … in 
    if a2 
    then result1 
    else foo3() 
and foo3() = … (* etc *) 

यह अभी भी एक छोटे से बोझिल हो सकता है जब लेखन:

सरल है, जो दोनों भाषाओं में काम करता है, कई उप कार्यों (*) में अपने कार्य शरीर में कटौती, और निरंतरता का उपयोग है ऑब्जेक्ट विधियों, लेकिन आप विधि स्कोप के भीतर "इंडेंटेशन बैलेंस" प्राप्त करने के लिए हमेशा आंतरिक कार्यों का उपयोग कर सकते हैं।

यह भी ध्यान दें कि rec कीवर्ड स्रोत लेआउट में प्रत्येक निरंतरता को अपने कॉलर का पालन करने की अनुमति देने के एकमात्र उद्देश्य के लिए है, यहां कोई असली रिकर्सन नहीं है।


(*): @gsg ने टिप्पणियों में भी इसका उल्लेख किया।

5

, OCaml में कोई return बयान नहीं है, हालांकि आप अपवाद की मदद से एक का अनुकरण कर सकते हैं:

let foo() = 
let a1 = lazy ... 
and a2 = lazy ... 
and a3 = lazy ... 
in 
match a1, a2, a3 with 
| lazy true, _, _ -> result1 
| _, lazy true, _ -> result2 
| _, _, lazy true -> result3 
| _, _, _ -> result4 

:

exception Ret of t 

let my_ret x = raise (Ret x) 

let foo() = 
try 
    let a1 = ... in 
    if a1 then my_ret result1; 
    let a2 = ... in 
    if a2 then my_ret result2; 
    ... 
with Ret x -> x 

एक अन्य उपयोगी समाधान आलसी मूल्यांकन का उपयोग किया जाएगा यह आलसी का उपयोग करने वाले उदाहरणों में से एक है, शायद आपकी गणना व्यक्त करने का अधिक संक्षिप्त तरीका है।

5

कोर पुस्तकालय एक with_return समारोह, कि तुम समारोह से एक गैर-स्थानीय मौजूद करने की अनुमति देता प्रदान करता है:

open Core_kernel.Std 
let foo() = with_return (fun goto -> 
    if a1 then goto.return 1; 
    if a2 then goto.return 2; 
    if a3 then goto.return 3; 
    if a4 then goto.return 4; 
    if a5 then goto.return 5; 
    return 6) 

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

let foo() = [ 
    clause1, expr1; 
    clause2, expr2; 
    clause3, expr3; 
] |> List.Assoc.find true 
    |> Option.value ~default:expr4 
बेशक में

इस मामले में आपके पास शॉर्ट-सर्किट मूल्यांकन नहीं है। आप इसे आलसी मूल्यांकन या थंक्स के साथ ठीक कर सकते हैं। लेकिन जब तक कि आपकी गणना वास्तव में भारी न हो या साइड इफेक्ट्स न दें, यह इसके लायक नहीं है।

0

if अभिव्यक्तियों के विपरीत, match क्लॉज फ़ंक्शन के अंत तक विस्तारित होते हैं, भले ही उनमें ब्रैकेट की आवश्यकता के बिना एकाधिक कथन शामिल हों। तो अगर आप कर सकते हैं:

let foo() = 
    match ... with 
    | true -> result1 
    | false -> 
    match ... with 
    | true -> result2 
    | false -> 
    match ... with 
    | true -> result3 
    | false -> 
    match ... with 
    | true -> result4 
    | false -> result5 

आप नहीं दिखाया जहां result1 अपने उदाहरण में से आता है, तो मुझे यकीन है कि नहीं किया जा सकता, लेकिन आप इसे बेहतर है ... बल्कि परिणाम के साथ एक विकल्प लौट मिल सकती है एक बूल की तुलना में, उदाहरण के लिए

let foo() = 
    match ... with 
    | Some result1 -> result1 
    | None -> 
    ... 
संबंधित मुद्दे