2010-01-30 6 views
8

तो मैंने अपने पहले एफ # प्रोग्राम को पूरा करने के बारे में बताया है, मेरी केवल कार्यात्मक पृष्ठभूमि हैस्केल के ज्ञान के थोड़ा (पढ़ें: इसमें वास्तव में कोई प्रोग्राम नहीं बनाया है)।एफ #: मुझे कोई तर्क लेने वाले कार्यों के लिए स्पष्ट रूप से 'इकाई' निर्दिष्ट क्यों करना है?

prepareDeck = allSuits |> List.collect generateCards |> shuffle 

और

prepareDeck() = allSuits |> List.collect generateCards |> shuffle 

मैंने देखा है कि यह "कैश" पूर्व, यह कभी नहीं recalculating यदि:

कुछ boggling व्यवहार का सामना कर के बाद, मैं एहसास है कि एफ # जो भेदभाव करता है आया इसे दोबारा कहा जाता है, जबकि यह बाद वाले को सामान्य कार्य की तरह व्यवहार करता है। यदि आप प्रश्न में कार्य के साइड इफेक्ट्स नहीं हैं, तो आप अंतर नहीं बता सकते हैं, लेकिन मेरे shuffle ने किया!

क्या यह सामान्य ज्ञान होना चाहिए था? मैंने अभी तक किसी भी ट्यूटोरियल सामग्री पर इसका उल्लेख नहीं देखा है। क्या पार्सर में सिर्फ एक कमजोरी है, थोड़ी सी तरह से आप में का उपयोग करने से पहले एक फ़ंक्शन घोषित करने के लिए है?

उत्तर

15

अधिकांश एफ # सामग्री बताती है कि मॉड्यूल में सभी शीर्ष-स्तरीय बयानों को घोषणा पर शीर्ष-नीचे से निष्पादित किया जाता है। दूसरे शब्दों में, जो आपने घोषित किया है वह एक फ़ंक्शन नहीं है, लेकिन एक मूल्य जो प्रोग्राम चलाता है, एक बार बाध्य होता है।

यह वास्तव में परावर्तित कोड देखने में मदद करता है। अन्य एक समारोह है

public static string juliet 
{ 
    [CompilerGenerated, DebuggerNonUserCode] 
    get 
    { 
     return "awesome"; 
    } 
} 

//... 

public static string juliet2() 
{ 
    return "awesome"; 
} 

तो एक एक स्थिर संपत्ति है,:

let juliet = "awesome" 
let juliet2() = "awesome" 

संकलित कोड कुछ इस तरह दिखता है: मैं एक साधारण फ़ाइल है।

let x = someLongRunningDatabaseCall() 

हम केवल चाहते x एक बार बाध्य होने के लिए, हम इसे लागू करने की डेटाबेस समारोह हर हम का उपयोग x नहीं करना चाहती: कल्पना क्योंकि अगर हम कुछ इस तरह था यह एक वांछनीय संपत्ति है।

इसके अतिरिक्त, हम इस तरह दिलचस्प कोड लिख सकते हैं:

> let isInNebraska = 
    printfn "Creating cities set" 
    let cities = set ["Omaha"; "Bellevue"; "Lincoln"; "Papillion"; "La Vista"; "Ralston"] 
    fun n -> cities.Contains(n);; 
Creating cities set 

val isInNebraska : (string -> bool) 

> isInNebraska "Omaha";; 
val it : bool = true 

> isInNebraska "Okaloosa";; 
val it : bool = false 

isInNebraska के बाद से एक मूल्य है, इसके तुरंत मूल्यांकन किया जाता है। ऐसा ही होता है कि इसकी डेटाटाइप (string -> bool) है, इसलिए यह एक फ़ंक्शन की तरह दिखता है। नतीजतन, हम केवल cities को एक बार सेट करते हैं भले ही हम फ़ंक्शन 1000 बार बुलाएं।

चलो इस के लिए कि कोड की तुलना करें:

> let isInNebraska2 n = 
    printfn "Creating cities set" 
    let cities = set ["Omaha"; "Bellevue"; "Lincoln"; "Papillion"; "La Vista"; "Ralston"] 
    cities.Contains(n);; 

val isInNebraska2 : string -> bool 

> isInNebraska2 "Omaha";; 
Creating cities set 
val it : bool = true 

> isInNebraska2 "Okaloosa";; 
Creating cities set 
val it : bool = false 

ओह, हमें एक नए शहरों सेट हर हम समारोह आह्वान बना रहे हैं।

तो निश्चित रूप से मूल्यों और कार्यों के बीच एक वैध और वास्तविक भेद है।

+1

अच्छा उदाहरण। रुचि रखने वाले किसी भी व्यक्ति के लिए, "विशेषज्ञ एफ #" पुस्तक (अध्याय 8) कुशल आंशिक अनुप्रयोग के लिए कार्यों को डिजाइन करने के संदर्भ में इस चर्चा को थोड़ा आगे बढ़ाती है। – itowlson

+1

मुझे लगता है कि यहां कोई दोष है: स्थिर संपत्ति के बीच कोई अंतर नहीं है और उसमें एक स्थिर विधि ** दोनों दृश्यों के पीछे ** विधियां हैं, और एक संपत्ति तक पहुंच वास्तव में एक विधि कॉल है (यही कारण है कि आप चिह्नित कर सकते हैं * वर्चुअल * के रूप में एक संपत्ति)। मैं आपकी "वांछनीय संपत्ति" नहीं देख सकता। –

+1

मेरा मानना ​​है कि अंतर यह है कि जब आपने 'julietNoFunction = ...' स्थिर संपत्ति को स्थिर क्षेत्र पर संग्रहीत एक मूल्य वापस कर दिया है, और यह मान केवल जेनरेट किए गए प्रकार के स्थिर निर्माता पर गणना की जाती है मॉड्यूल। मुझे लगता है कि मैंने इसे परावर्तक में देखा है, लेकिन अब मुझे यकीन नहीं है। वैसे भी, जिस तरह से आप इसे पेश करते हैं, वह 'जूलियट = ...' पर 'जूलियट() = ...' का उपयोग करने पर किसी भी फायदे को प्रदर्शित नहीं करता है। –

6

इस तरह चीजें साइड इफेक्ट्स के साथ व्यावहारिक रूप से हर भाषा में काम करती हैं।

let name = expr 

कोड 'अब' चलाता है, और अगर expr असर पड़ता है दुष्प्रभाव हो सकता है। name के बाद के संदर्भों का कोई प्रभाव नहीं है। जबकि

let name() = expr 

एक समारोह को परिभाषित करता है, अब कोई प्रभाव है, और मूल्यांकन (और प्रभाव है) होगा हर बार name() शुरू हो जाती है।

+0

गोचा। मान लीजिए कि मैं उलझन में था क्योंकि एफ # पहली भाषा है जिसका मैंने उपयोग किया है जो कार्यात्मक लेकिन दुष्प्रभावपूर्ण है। –

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

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