2016-07-14 15 views
10

मैं में map() सरणी के समारोह का उपयोग कर रहा पाश के लिए में इस तरह का उपयोग करना:,में बंद अनुगामी के लिए में पाश

Use of unresolved identifier 'doubled'

लेकिन अगर मैं:

let numbers = [2, 4, 6, 8, 10] 

for doubled in numbers.map { $0 * 2 } // compile error 
{ 
    print(doubled) 
} 

जो पैदा करता है त्रुटि संकलन map() फ़ंक्शन के लिए ब्रांडेसिस डालें, यह ठीक काम करता है। अर्थात

for doubled in numbers.map ({ $0 * 2 }) 
{ 
    print(doubled) 
} 

मेरा प्रश्न है, क्यों समारोह और पाश अनुगामी के कोड ब्लॉक अंतर संकलक नहीं होता, इस समस्या का कारण है यह सोचते हैं?

उत्तर

9

ऐसा इसलिए है क्योंकि संदर्भ के रूप में अस्पष्टता होगी जिसमें पीछे की ओर कार्य करना चाहिए। एक वैकल्पिक वाक्य रचना जो काम करता है:

let numbers = [2, 4, 6, 8, 10] 

for doubled in (numbers.map { $0 * 2 }) // All good :) 
{ 
    print(doubled) 
} 

मैं कहूंगा कि यह संभावना है क्योंकि 'में' ऑपरेटर कार्यों अनुगामी तुलना में एक उच्च पूर्वता है।

यह आपके ऊपर है जो आपको लगता है कि अधिक पठनीय है।

+0

यह एक सुंदर चाल है। –

8

पीछे हटने वाला व्याकरण बयान के एक शरीर के बीच एक ज्ञात अस्पष्टता उत्पन्न करता है (आपके मामले में, यह for लूप है, लेकिन यह अन्य कथनों पर भी लागू होता है) और पिछला बंद करने का शरीर। हालांकि यह इस समस्या, compiler designers decided to prohibit trailing closure syntax in controlling portions of various high-level statements हल करने के लिए तकनीकी रूप से संभव है:

While it would be possible to tell what is intended in some cases by performing arbitrary lookahead or by performing type checking while parsing, these approaches have significant consequences for the architecture for the compiler. As such, we've opted keep the parser simple and disallow this.

संघर्ष की प्रकृति को समझने के लिए, इस उदाहरण पर विचार करें:

for v in expr { /* code 1 */ } { /* code 2 */ } 

पार्सर code 1 ब्लॉक के बारे में एक विकल्प बनाने की जरूरत है। यह या तो expr के अनुगामी बंद के रूप में उपयोग कर सकते हैं और for लूप के शरीर के रूप में code 2 का इलाज, या for लूप के शरीर के रूप में code 1 उपयोग करते हैं, जबकि घुंघराले ब्रेसिज़ में संलग्न बयान के एक स्वतंत्र समूह के रूप में code 2 इलाज - एक क्लासिक shift-reduce conflict

ऐसे संघर्षों को हल करना बहुत महंगा है। अनिवार्य रूप से, आपके पार्सर को अधिक टोकन के माध्यम से आगे बढ़ना जारी रखना चाहिए, जब तक केवल एक व्याख्या समझ में न हो, या पार्सर टोकन से बाहर हो जाता है (इस मामले में यह एक मनमाने ढंग से निर्णय एक तरफ या दूसरे बनाता है, जिसके लिए प्रोग्रामर को अपने कार्यक्रम को असंबद्ध करने की आवश्यकता होती है वह विकल्प वह नहीं है जो वे चाहते थे)।

कोष्ठक जोड़ना अस्पष्टता को हटा देता है। प्रस्ताव, एक अनिवार्य कीवर्ड उसके शरीर से पाश के नियंत्रण भाग को अलग करने जोड़कर अस्पष्टता को दूर करने पर विचार किया गया यानी

// The syntax of rejected proposal 
for doubled in numbers.map { $0 * 2 } do { 
    print(doubled) //     ^^ 
} 

एक अतिरिक्त do कीवर्ड को जोड़ने बाईं ओर स्थित "देता" ब्लॉक, यदि कोई हो, के लिए अभिव्यक्ति, और दाईं ओर ब्लॉक को लूप स्टेटमेंट के शरीर को बनाता है। इस दृष्टिकोण में एक बड़ी कमी है, क्योंकि यह एक तोड़ने वाला बदलाव है। यही कारण है कि इस प्रस्ताव को खारिज कर दिया गया है।

+0

विस्तृत स्पष्टीकरण के लिए धन्यवाद। –

+0

@ एम। हसन आपका स्वागत है! मैंने सोचा कि चूंकि आपके पास पहले से ही एक अच्छा काम है, इसलिए मुझे संकलक लेखक के परिप्रेक्ष्य से समस्या की प्रकृति पर ध्यान देना चाहिए। – dasblinkenlight

2

वाक्यविन्यास संदिग्ध है (dasblinkenlight's answer देखें)।एक विकल्प के वाक्य रचना के लिए:

let numbers = [2, 4, 6, 8, 10] 

numbers.map { $0 * 2 }.forEach { 
    print(doubled) 
} 

या

let numbers = [2, 4, 6, 8, 10] 
let doubledNumbers = numbers.map { $0 * 2 } 

for doubled in doubledNumbers { 
    print(doubled) 
} 
+2

यह एक कार्यात्मक दृष्टिकोण नहीं है। यह सिर्फ एक विधि है। (प्रत्येक के लिए एक कार्यात्मक, यदि ऐसी कोई चीज़ मौजूद थी, तो कुछ उपयोगी हो जाएगी, साइड इफेक्ट पर भरोसा नहीं करेगा।) मैं केवल बिंदु बना रहा हूं क्योंकि मैं उन स्थानों पर 'प्रत्येक के लिए' पॉप अप देख रहा हूं जहां यह अनुचित है (ज्यादातर मामलों में, ' फॉर-इन 'बहुत बेहतर स्विफ्ट है), और मुझे संदेह है कि "यह कार्यात्मक तरीका है" एक कारण है। इस मामले में, मानचित्र/फ़िल्टर श्रृंखला के अंत में, यह उपयोगी हो सकता है, लेकिन ऐसा नहीं क्योंकि यह कार्यात्मक प्रोग्रामिंग पर आधारित है (यह विपरीत है); सिर्फ इसलिए कि सिंटैक्स कभी-कभी मानचित्र/फ़िल्टर चेन के साथ थोड़ा सा अच्छा होता है। –

+0

@RobNapier मैं सहमत हूं कि 'के लिए' पूरी तरह कार्यात्मक नहीं है (हालांकि कई प्रोग्रामर इसे कार्यात्मक कहते हैं क्योंकि आप इसे एक फ़ंक्शन पास कर सकते हैं और "कार्यात्मक" शब्द बिल्कुल अच्छी तरह परिभाषित नहीं है)। हालांकि, मैं 'इन-इन' से बेहतर 'इन-इन' से बेहतर नहीं हूं। 'इन-इन' बेहतर कैसे है? – Sulthan

+2

यह वापसी/ब्रेक/जारी रखने का सम्मान करता है ('वापसी' के 'प्रत्येक' इलाज के लिए कई देवताओं को आश्चर्यचकित होने की संभावना है)। यह बंद कैप्चर नहीं करता है। यह स्विफ्ट फ्लो-कंट्रोल के बाकी हिस्सों से मेल खाता है (अगर, करते हैं, जबकि, दोहराना)। मुझे नहीं लगता कि यह एक दुर्घटना है कि स्विफ्ट प्रोग्रामिंग भाषा पुस्तक 'मानचित्र' और 'इन-इन' बताती है, लेकिन 'प्रत्येक के लिए' का उल्लेख नहीं करती है। "एईच (मुश्किल से) खुद के लिए भुगतान करता है" के बारे में क्लैटनर की टिप्पणियां भी देखें क्योंकि आप इसे गैर-अज्ञात फ़ंक्शन पास कर सकते हैं। https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151214/003388.html। –

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