2012-03-25 11 views
8

मैंने एक उलटा स्ट्रिंग प्राप्त करने के लिए एक स्ट्रिंग पास करने का प्रयास किया। मैं ऐसा क्यों नहीं कर सकता:तारों के लिए OCaml फ़ंक्शन पैरामीटर पैटर्न मिलान

let rec reverse x = 
    match x with 
    | "" -> "" 
    | e^s -> (reverse s)^e;; 

कंपाइलर का कहना है कि यह एक वाक्यविन्यास त्रुटि है। क्या मैं पैरामीटर को नष्ट करने के लिए ^ का उपयोग नहीं कर सकता?

+0

: जहां स्ट्रिंग में संकलक भी स्ट्रिंग विभाजित करना चाहिए? "एबीसी" से "ए" "बीसी" या "एबी" "सी" – 0x434D53

उत्तर

15

इसका कारण यह है कि तारों को सूटियों के समान ही डेटाटाइप के रूप में प्रदर्शित नहीं किया जाता है। इसलिए, जबकि विपक्ष (: :) एक कन्स्ट्रक्टर है,^ नहीं है। इसके बजाए, तारों को रिकर्सिव परिभाषा के बिना निम्न स्तर के प्रकार के रूप में दर्शाया जाता है (सूचियां हैं)। एसएमएल (जिसे आप ओकैम में लिख सकते हैं) नामक एक फ़ंक्शन का उपयोग करके तारों से मिलान करने का एक तरीका है, जिसे 'विस्फोट' और 'इंपोडोड' कहा जाता है - - विश्वसनीय रूप से - एक चार सूची में एक स्ट्रिंग लें और इसके विपरीत । Here's an example implementation of them.

+0

धन्यवाद। लेकिन फिर भी सी ++ की तरह ऑपरेंड 'ओवरलोड' करने के लिए है? यह निश्चित रूप से अमूर्त बेहतर होगा। – lkahtz

+1

नहीं। ऑपरेटर को अधिभारित करने का कोई तरीका नहीं है। स्ट्रिंग्स को निम्न स्तर के प्रकार के रूप में परिभाषित किया जाता है, और जब आप मौलिक रूप से एक अनिवार्य रूप से परिभाषित प्रकार नहीं हैं तो आप उन्हें कृत्रिम रूप से डेटाटाइप में लगा सकते हैं। –

1

जब आप एक पैटर्न मिलान अभिव्यक्ति लिखते हैं, तो आप अपने पैटर्न में मनमानी कार्यों का उपयोग नहीं कर सकते हैं। आप केवल कन्स्ट्रक्टर का उपयोग कर सकते हैं, जो अनचाहे फ़ंक्शंस जैसा दिखता है। उदाहरण के लिए, फ़ंक्शन "+" को पूर्णांक पर परिभाषित किया गया है। तो अभिव्यक्ति 1+2 का मूल्यांकन किया गया है और 3 देता है; फ़ंक्शन "+" का मूल्यांकन किया जाता है, इसलिए आप x+y पर मेल नहीं खा सकते हैं। यहाँ प्राकृतिक संख्या पर एक समारोह परिभाषित करने की कोशिश की जाँच करता है कि संख्या शून्य है कि क्या है:

let f x = match x with 
    | 0 -> false 
    | a+1 -> true 
;; 

यह काम नहीं कर सकते हैं! इसी कारण से, तारों के साथ आपका उदाहरण काम नहीं कर सकता है। समारोह "^" का तार तारों पर मूल्यांकन किया जाता है, यह एक निर्माता नहीं है।

x+1 पर मिलान काम करेगा ही अगर संख्या unevaluated प्रतीकात्मक unevaluated ऑपरेटर + और एक प्रतीकात्मक निरंतर 1 से बाहर कर दिया भाव थे। ओसीएएमएल में यह मामला नहीं है। इंटीजर सीधे मशीन नंबरों के माध्यम से लागू किए जाते हैं।

जब आप एक प्रकार के प्रकार से मेल खाते हैं, तो आप रचनाकारों से मेल खाते हैं, जो अनियमित अभिव्यक्तियां हैं। उदाहरण के लिए:

# let f x = match x with 
    | Some x -> x+1 
    | None -> 0 
;; 
val f : int option -> int = <fun> 

यह काम करता है क्योंकि 'a option प्रकार इस तरह के Some x के रूप में, एक प्रतीकात्मक अभिव्यक्ति से बाहर कर दिया गया है। यहां, Some एक ऐसा फ़ंक्शन नहीं है जिसका मूल्यांकन किया जाता है और कुछ अन्य मूल्य देता है, बल्कि एक "कन्स्ट्रक्टर" देता है, जिसे आप किसी फ़ंक्शन के रूप में सोच सकते हैं जिसका मूल्यांकन कभी नहीं किया जाता है। अभिव्यक्ति Some 3 का मूल्यांकन किसी भी आगे नहीं किया गया है; यह वैसे ही रहता है। यह केवल ऐसे कार्यों पर है कि आप पैटर्न-मिलान कर सकते हैं।

सूचियां रचनाकारों से निर्मित प्रतीकात्मक, अनियमित अभिव्यक्तियां भी हैं; निर्माता :: है। x :: y :: [] का परिणाम एक अनौपचारिक अभिव्यक्ति है, जिसे कॉस्मेटिक सुविधा के लिए केवल [x;y] सूची द्वारा दर्शाया गया है। इस कारण से, आप सूचियों पर पैटर्न-मिलान कर सकते हैं।

+0

आपके उत्तर के लिए धन्यवाद। यह अच्छा होगा अगर आप उल्लेख कर सकते हैं कि OCaml में स्ट्रिंग पर स्ट्रिंग मिलान करना संभव है या नहीं। –

1

Kristopher Micinski explained के रूप में, आप तारों पर पैटर्न मिलान नहीं कर सकते क्योंकि वे सूचियां नहीं हैं।

लेकिन आप explode का उपयोग करके उन्हें सूचियों में परिवर्तित कर सकते हैं।

let rec reverse str = 
    match explode str with 
    [] -> "" 
    | h::t -> reverse (implode t)^string_of_char h 

इस तरह यह प्रयोग करें:: यहाँ explode और अपने समकक्ष implode का उपयोग कर पैटर्न मिलान के साथ अपने reverse समारोह है

let() = 
    let text = "Stack Overflow ♥ OCaml" in 
    Printf.printf "Regular: %s\n" text; 
    Printf.printf "Reversed: %s\n" (reverse text) 

कौन से पता चलता है कि यह सिंगल-बाइट वर्ण के लिए काम करता है लेकिन मल्टी-बाइट लोगों के लिए नहीं ।

और यहाँ explode और implode एक सहायक विधि के साथ-साथ हैं:

let string_of_char c = String.make 1 c 

(* Converts a string to a list of chars *) 
let explode str = 
    let rec explode_inner cur_index chars = 
    if cur_index < String.length str then 
     let new_char = str.[cur_index] in 
     explode_inner (cur_index + 1) (chars @ [new_char]) 
    else chars in 
    explode_inner 0 [] 

(* Converts a list of chars to a string *) 
let rec implode chars = 
    match chars with 
    [] -> "" 
    | h::t -> string_of_char h^(implode t) 
नीचे विवरण के लिए इसके अतिरिक्त
संबंधित मुद्दे