2013-04-05 10 views
12

OCaml में, यह .mli में है करने के लिए कानूनी है:η विस्तार

val f : 'a -> 'a 
val g : 'a -> 'a 

और .ml:

let f x = x 
let g = f 
एफ # में

फिर भी, यह अस्वीकार कर दिया गया है:

eta_expand.ml(2,5): error FS0034: Module 'Eta_expand' contains 
    val g : ('a -> 'a)  
but its signature specifies 
    val g : 'a -> 'a  

The arities in the signature and implementation differ. The signature specifies that 'g' is function definition or lambda expression accepting at least 1 argument(s), but the implementation is a computed function value. To declare that a computed function value is a permitted implementation simply parenthesize its type in the signature, e.g. 
    val g: int -> (int -> int) 
instead of 
    val g: int -> int -> int. 

एक वर्कअराउंड जी की परिभाषा को बढ़ाने के लिए है:

let g x = f x 

अगर मेरे कोड (पूरी तरह कार्यात्मक (कोई अपवाद नहीं, कोई साइड इफेक्ट, आदि) इस बराबर होना चाहिए वास्तव में, इसे और भी बेहतर कैसे भाषा प्रकार पर निर्भर करता है सामान्यीकरण करता बहुरूपता के संबंध में हो सकता है,: OCaml में आंशिक अनुप्रयोग polymorphic कार्यों का उत्पादन नहीं करते हैं, लेकिन उनके η-विस्तार करता है)।

क्या व्यवस्थित η-विस्तार के लिए कोई कमी है?

दो उत्तरों η-विस्तार :-) पर प्रश्न को हल करते हैं और इसके बजाय सुझाव देते हैं कि मैं अपने कार्यात्मक प्रकार के चारों ओर कोष्ठक जोड़ता हूं। ऐसा इसलिए है क्योंकि जाहिर है, एफ # कार्यों की "सत्य" परिभाषा के बीच टाइपिंग स्तर पर भिन्न होता है (जैसे λ-expressions और गणना की परिभाषाएं, आंशिक अनुप्रयोगों में); संभवतः ऐसा इसलिए है क्योंकि λ-expressions सीधे सीएलआर कार्यों को मानचित्र करते हैं जबकि गणना की गई परिभाषाएं वस्तुओं को प्रतिनिधि करने के लिए मानचित्र बनाती हैं। (मैं इस व्याख्या के बारे में सुनिश्चित नहीं कर रहा हूँ और अगर किसी को एफ # से परिचित दस्तावेजों इस का वर्णन संदर्भ को इंगित सराहना करेंगे।)

एक समाधान व्यवस्थित .mli में सभी समारोह प्रकार को कोष्ठकों जोड़ने के लिए होगा, लेकिन मुझे डर है कि इससे अक्षमता हो सकती है। एक और गणना गणना कार्यों का पता लगाने और .mli में संबंधित प्रकारों को संश्लेषित करना होगा। एक तीसरा समाधान स्पष्ट मामलों को विस्तारित करना होगा, और दूसरों को संश्लेषित करना होगा।

मैं एफ #/सीएलआर आंतरिक के साथ पर्याप्त परिचित नहीं हूं, यह मापने के लिए कि कौन से महत्वपूर्ण प्रदर्शन या जुर्माना लगा रहे हैं।

+2

बस इसे 'वैल जी: (' ए -> 'ए)' बनाओ। यह एफ # प्रकार प्रणाली की एक ज्ञात विशेषता/बग है। –

+0

फिर से, "बस इसे बनाएं" - संभवतः अगर λ-expressions और computed कार्यों में विस्थापन योग्य प्रकार नहीं हैं, तो यह अच्छे कारण के लिए है। इसके अलावा, यह स्वत: उत्पन्न कोड है, इस प्रकार मामला मैन्युअल रूप से कुछ कोष्ठक जोड़ने से थोड़ा अधिक जटिल है ... –

+0

इस मामले में दोनों के बीच एक अंतर है, एक विधि में संकलित किया गया है और दूसरा स्थिर ' Func 'संपत्ति। संगतता बिडरेक्शनल नहीं है (यानी, 'ए -> बी: <: (a -> बी) ', लेकिन नहीं' (ए -> बी): <: a -> बी')। –

उत्तर

4

दिलचस्प बात यह है मेरी fsi एक और अधिक उपयोगी त्रुटि संदेश देता है: आप g :('a -> 'a) सभी पाने के लिए कोष्ठक जोड़ देते हैं तो

/test.fs(2,5): error FS0034: Module 'Test' contains 
    val g : ('a -> 'a) but its signature specifies 
    val g : 'a -> 'a The arities in the signature and implementation differ. 
      The signature specifies that 'g' is function definition or lambda expression 
      accepting at least 1 argument(s), but the implementation is a computed 
      function value. To declare that a computed function value is a permitted 
      implementation simply parenthesize its type in the signature, e.g. 
     val g: int -> (int -> int) instead of 
     val g: int -> int -> int. 

ठीक

+1

मैंने ब्रेवटी के लिए त्रुटि संदेश का अंत बंद कर दिया था। मैं "सब ठीक है" से असहमत हूं। :-) –

8

सिद्धांत रूप में है, एफ # समारोह प्रकार 'a -> 'b -> 'c'a -> ('b -> 'c) रूप में एक ही प्रकार है। यही है, एफ # में करीबी रूप का उपयोग करके एकाधिक तर्क फ़ंक्शंस का प्रतिनिधित्व किया जाता है। आप एक ऐसे मामले का उपयोग कर सकते हैं जहां अन्य मामलों में अन्य की अपेक्षा की जाती है उदा। उच्च आदेश समारोह को कॉल करते समय।

हालांकि, व्यावहारिक कारणों से, एफ # कंपाइलर वास्तव में प्रकारों के बीच अंतर करता है - प्रेरणा यह है कि वे संकलित .NET कोड में अलग-अलग प्रतिनिधित्व करते हैं। इसका प्रदर्शन पर प्रभाव पड़ता है और सी # के साथ अंतःक्रियाशीलता भी होती है, इसलिए यह भेद बनाने में उपयोगी होता है।

एक समारोह Foo : int -> int -> int एक सदस्य int Foo(int, int) के रूप में संकलित किया जा रहा है - संकलक डिफ़ॉल्ट रूप से curried फार्म का उपयोग नहीं करता है, क्योंकि यह अधिक कुशल जब दोनों तर्क के साथ Foo (अधिक आम मामले) बुला है और यह इंटरॉप के लिए बेहतर है ।एक फ़ंक्शन Bar : int -> (int -> int) को FSharpFunc<int, int> Bar(int) के रूप में संकलित किया जाएगा - वास्तव में करीबी रूप का उपयोग करके (और इसलिए इसे केवल एक पैरामीटर के साथ कॉल करने के लिए अधिक कुशल है और इसे सी # से उपयोग करना मुश्किल होगा)।

यही कारण है कि F # हस्ताक्षरों की बात करते समय समान प्रकार के समान व्यवहार नहीं करता है - हस्ताक्षर प्रकार निर्दिष्ट करता है, लेकिन यहां यह भी निर्दिष्ट करता है कि फ़ंक्शन को कैसे संकलित किया जा रहा है। कार्यान्वयन फ़ाइल को सही प्रकार के कार्य प्रदान करना है, लेकिन - इस मामले में - सही संकलित रूप भी।

+0

मैं अंतर को समझता हूं। जो मुझे नहीं पता वह सबसे अच्छा कामकाज है: क्या मुझे (ए) η- सभी गणना किए गए कार्यों का विस्तार करना चाहिए (बी) सभी गणना किए गए कार्यों के प्रकारों को संश्लेषित करना चाहिए? –

+0

@monniaux η- सभी गणना किए गए कार्यों का विस्तार करना मेरी डिफ़ॉल्ट पसंद होगी। लेकिन यह कई कारकों पर निर्भर करता है। यदि आप सी # इंटरऑपरेबिलिटी चाहते हैं तो निश्चित रूप से (ए), यदि आप अक्सर गणना किए गए कार्यों पर आंशिक अनुप्रयोग का उपयोग करते हैं तो (बी) आपको बेहतर प्रदर्शन देगा। –

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