छोटे वर्ड के लिए स्टैक को इधर-उधर करना ठीक है। लेकिन जब किसी वर्ड के कई इनपुट हों और आपको उन्हें नाम से इस्तेमाल करना हो, तो Factor लोकल देता है। ये नामित बाइंडिंग होती हैं, जो :: (वर्ड की परिभाषा के लिए) या [| | ] (इनलाइन लैम्ब्डा के लिए) से बनाई जाती हैं।
:: ( inputs -- outputs ): की जगह :: लगाइए, और इनपुट के नाम बॉडी में लोकल वेरिएबल बन जाते हैं:
USING: locals ;
:: hypotenuse ( a b -- c )
a a *
b b *
+ sqrt ;
इसकी तुलना स्टैक इधर-उधर करने वाले वर्शन से कीजिए:
! DOCTEST: SKIP (shown for comparison — would re-define hypotenuse)
: hypotenuse ( a b -- c )
[ sq ] bi@ + sqrt ;
दोनों ही सही हैं। लोकल तब खास काम आते हैं जब किसी इनपुट का इस्तेमाल एक से ज़्यादा बार हो, या जब ऑपरेशन करने का क्रम स्टैक के क्रम से अपने आप मेल न खाए।
:> से मध्यवर्ती वैल्यू बाइंड करनाकिसी :: वाली बॉडी के अंदर (या इनलाइन [| ... |] लैम्ब्डा में), :> डेटा स्टैक के ऊपर से एक वैल्यू उठाता है और उसे एक नए लोकल से बाँध देता है:
value :> name ! immutable binding
value :> name! ! mutable binding (name! is its setter)
बदले न जा सकने वाला रूप ही आम है। इसका इस्तेमाल किसी मध्यवर्ती वैल्यू को नाम देने के लिए कीजिए, ताकि बॉडी ऊपर से नीचे पढ़ी जा सके:
USING: locals math ;
:: average-3 ( x y z -- avg )
x y + z + :> sum
sum 3 / ;
! वाला रूप लोकल को बदले जा सकने वाला घोषित करता है। बॉडी में आगे कहीं value name! (न कोलन, न :>) उसे फिर से असाइन कर देता है:
USING: kernel locals math math.order ;
:: clamped ( x lo hi -- y )
x :> v!
v lo < [ lo v! ] when
v hi > [ hi v! ] when
v ;
बदले जा सकने वाले लोकल उन इटरेशन वर्ड के अंदर खास काम आते हैं जो आपको आगे के अभ्यासों में मिलेंगे (जैसे while)।
[let से कहीं भी स्कोप बनाइए:> सिर्फ किसी लेक्सिकल स्कोप के अंदर ही काम करता है। ऐसा स्कोप :: और [| ... |] अपने आप बना देते हैं। अगर आपको किसी सादे : वर्ड से या लिसनर पर लोकल बनाने हों, तो कोड को [let ... ] में लपेट दीजिए:
[let code :> name code :> name ... body ]
हर :> name पिछले एक्सप्रेशन की स्टैक के सबसे ऊपर की वैल्यू को बाँध देता है। ये बाइंडिंग बाकी पूरे फॉर्म को दिखती हैं।
USING: locals math ;
[let 3 :> x 4 :> y x x * y y * + ] . ! => 25
[let स्टैक वाली : परिभाषाओं और नामित बाइंडिंग के बीच पुल का काम करता है। यह तब काम आता है जब किसी वर्ड के सिर्फ एक हिस्से को ही लोकल से फायदा मिलता हो।
[| inputs | body ]
किसी कोटेशन के अंदर, [| inputs | body ] ऐसे लोकल बनाता है जिन्हें बॉडी नाम से इस्तेमाल कर सकती है। यह खास तौर पर assoc-map जैसे हायर-ऑर्डर वर्ड के साथ काम आता है, जिसका कोटेशन key और value दोनों पाता है:
USING: assocs locals ;
H{ { "a" 1 } { "b" 2 } }
[| key value | key value neg ] assoc-map .
! => H{ { "a" -1 } { "b" -2 } }
यही तरीका map-index के लिए भी चलता है (जो [sequences][sequences] में है), जिसका कोटेशन एलिमेंट और उसका इंडेक्स दोनों पाता है। नाम से साफ हो जाता है कि कौन-सा ऑपरैंड कौन-सी भूमिका निभाता है:
USING: locals sequences ;
! Divide each element by its 1-based position:
{ 10 80 270 } [| elt i | elt i 1 + / ] map-index .
! => { 10 40 90 }
लैम्ब्डा का स्टैक इफेक्ट इस बात से तय होता है कि उसे कौन-कौन से इनपुट मिलते हैं और उसकी बॉडी क्या बनाती है।
लोकल का इस्तेमाल तब कीजिए जब:
dup/swap/rot पढ़ने में मुश्किल लगते हों।assoc-map में)।जब बॉडी का काम सीधा-सरल क्रम में चलता हो, तो सादी : परिभाषाएँ छोटी भी रहती हैं और पढ़ने में कम से कम उतनी ही आसान होती हैं।
assoc-map, एक बार में एक एंट्रीassoc-map (जो assocs में है) किसी एसोसिएटिव कलेक्शन की हर एंट्री पर एक कोटेशन लगाता है:
assoc-map ( assoc quot: ( key value -- newkey newvalue ) -- newassoc )
ऐसा कोटेशन लिखने का सबसे साफ तरीका लोकल वाला लैम्ब्डा है।
cond को फिर से देखिएजब आपको f या किसी संख्यात्मक वैल्यू को देखकर तय करना हो कि क्या करना है, तो cond बिल्कुल सही रूप है। यहाँ case की ज़रूरत नहीं पड़ती, क्योंकि तुलना करने के लिए कोई एक वैल्यू ही नहीं है।
आप फिर से रसोई में हैं और Leah's Luscious Lasagna की लसान्या रेसिपी को और निखार रहे हैं। यहाँ के काम आपसे एक साथ कई इनपुट सँभालने को कहते हैं, और ठीक ऐसे ही मौकों पर लोकल्स काम आते हैं, यानी Factor के नाम वाले बाइंडिंग।
cooking-status बनाइए जो स्टैक से टाइमर की रीडिंग ले और एक स्टेटस स्ट्रिंग लौटाए।
0 → "Lasagna is done."
f (टाइमर कभी सेट नहीं हुआ था) → "You forgot to set the timer."
"Not done, please wait."
12 cooking-status . ! => "Not done, please wait."
0 cooking-status . ! => "Lasagna is done."
f cooking-status . ! => "You forgot to set the timer."
preparation-time बनाइए जो परतों के नामों का एक ऐरे और हर परत के लिए औसत मिनटों की संख्या ले, और तैयारी का कुल समय लौटाए।
{ "sauce" "noodles" "sauce" "meat" "mozzarella" "noodles" } 3 preparation-time .
! => 18
quantities बनाइए जो परतों के नामों का एक ऐरे ले और दो वैल्यू लौटाए: ज़रूरी नूडल्स के ग्राम (हर नूडल परत के लिए 50 ग्राम) और ज़रूरी सॉस के लीटर (हर सॉस परत के लिए 1/5 लीटर)।
{ "sauce" "noodles" "sauce" "meat" "mozzarella" "noodles" } quantities .s
! => 100
! => 2/5
आपका दोस्त सामग्री की एक सूची भेजता है; उसमें अंतिम चीज़ उसकी गुप्त सामग्री है। add-secret-ingredient बनाइए जो उसकी सूची और आपकी सूची ले, और आपकी सूची लौटाए जिसमें गुप्त सामग्री जोड़ दी गई हो।
{ "noodles" "sauce" "mozzarella" "kampot pepper" }
{ "noodles" "meat" "sauce" "mozzarella" }
add-secret-ingredient .
! => { "noodles" "meat" "sauce" "mozzarella" "kampot pepper" }
कुकबुक की रेसिपी से दो हिस्से बनते हैं। scale-recipe बनाइए जो एक रेसिपी (सामग्री के नाम से मात्रा तक का हैशटेबल) और हिस्सों की लक्ष्य संख्या ले, और नाप के अनुसार बढ़ी हुई नई रेसिपी लौटाए।
H{ { "noodles" 200 } { "sauce" 1/2 } { "mozzarella" 1 } { "meat" 100 } }
4 scale-recipe .
! => H{ { "noodles" 400 } { "sauce" 1 } { "mozzarella" 2 } { "meat" 200 } }
Exercism पर साइन अप कीजिए और Factor को 47 कॉन्सेप्ट163 अभ्यास तथा असली इंसानों से मिलने वाली मेंटरिंग के साथ सीखिए और उसमें महारत हासिल कीजिए, वह भी बिल्कुल मुफ्त।