टेम्पलेट हास्केल के बारे में इतना बुरा क्या है?


252

ऐसा लगता है कि टेम्पलेट हास्केल को अक्सर हास्केल समुदाय द्वारा एक दुर्भाग्यपूर्ण सुविधा के रूप में देखा जाता है। इस संबंध में मैंने जो कुछ भी देखा है उसे शब्दों में बयां करना कठिन है, लेकिन इन कुछ उदाहरणों पर विचार करें

मैंने विभिन्न ब्लॉग पोस्ट देखे हैं जहां लोग टेम्पलेट हास्केल के साथ बहुत साफ-सुथरा सामान बनाते हैं, जिससे प्रीटीयर सिंटैक्स को सक्षम किया जाता है जो कि बस नियमित हास्केल में संभव नहीं होगा, साथ ही साथ जबरदस्त बॉयलरप्लेट की कमी भी होगी। तो ऐसा क्यों है कि टेम्प्लेट हास्केल को इस तरह से नीचे देखा जाता है? क्या यह अवांछनीय बनाता है? टेम्पलेट हास्केल से किन परिस्थितियों में बचा जाना चाहिए, और क्यों?


56
मैं वोट देने से असहमत हूं; मैं यह सवाल उसी भावना से पूछ रहा हूं जो मैंने पूछा था कि आलसी आई / ओ के बारे में इतना बुरा क्या है? और मैं उसी फैशन के जवाब देखने की उम्मीद करता हूं। मैं इस सवाल का जवाब देने के लिए तैयार हूं कि क्या इससे मदद मिलेगी।
दान बर्टन

51
@ErikPhilips आप उन लोगों को क्यों नहीं जाने देते जो इस टैग को अक्सर तय करते हैं कि यह यहाँ है? ऐसा लगता है जैसे हास्केल समुदाय के साथ आपकी एकमात्र बातचीत अपने सवालों को रखना है।
गैब्रियल गोंजालेज

5
@GabrielGonzalez ने वर्तमान प्रश्न के साथ यह स्पष्ट किया और उत्तर दिया कि यह पूछे जाने वाले प्रश्न का पालन नहीं करता है कि मुझे किस प्रकार का प्रश्न यहाँ नहीं पूछना चाहिए: हल करने के लिए कोई वास्तविक समस्या नहीं है । इस सवाल का कोई कोड विशिष्ट समस्या हल नहीं है और केवल प्रकृति में वैचारिक है। और सवाल के आधार पर मुझे टेम्पलेट हैस्केल से बचना चाहिए, यह भी स्टैक ओवरफ्लो में गिरता है एक सिफारिश इंजन नहीं है
एरिक फिलिप्स

27
@ErikPhilips अनुशंसा इंजन पहलू इस प्रश्न के लिए अप्रासंगिक है, क्योंकि आप देखेंगे कि इस तरह के विभिन्न उपकरणों के बीच एक निर्णय का जिक्र है (जैसे "मुझे बताएं कि मुझे किस भाषा का उपयोग करना चाहिए")। इसके विपरीत, मैं खासतौर पर टेम्पलेट हास्केल के बारे में स्पष्टीकरण के लिए पूछ रहा हूं, और अक्सर पूछे जाने वाले प्रश्न "यदि आपकी प्रेरणा है" मैं चाहूंगा कि अन्य लोग मुझे समझाएं "रिक्त", तो आप शायद ठीक हैं। " उदाहरण के लिए, GOTO अभी भी हानिकारक माना जाता है
डैन बर्टन

29
फिर से मतदान करना। सिर्फ इसलिए कि यह एक उच्च स्तर का प्रश्न है, इसका मतलब यह नहीं है कि यह एक अच्छा नहीं है।
ग्योर्गी एन्द्रसेक

जवाबों:


171

टेम्पलेट हास्केल से बचने का एक कारण यह है कि यह पूरी तरह से सुरक्षित नहीं है, इस प्रकार "हास्केल की भावना" के बहुत खिलाफ जा रहा है। इसके कुछ उदाहरण इस प्रकार हैं:

  • आपके पास इस बात पर कोई नियंत्रण नहीं है कि TH कोड का एक टुकड़ा Haskell AST किस प्रकार उत्पन्न होगा, जहां यह दिखाई देगा; आपके पास एक प्रकार का मान हो सकता है Exp, लेकिन आप नहीं जानते कि यह एक अभिव्यक्ति है जो एक [Char]या एक (a -> (forall b . b -> c))या जो भी प्रतिनिधित्व करता है । TH अधिक विश्वसनीय होगा यदि कोई व्यक्त कर सकता है कि एक फ़ंक्शन केवल एक निश्चित प्रकार के भाव उत्पन्न कर सकता है, या केवल फ़ंक्शन घोषणाएं, या केवल डेटा-निर्माता-मिलान पैटर्न, आदि।
  • आप ऐसे भाव उत्पन्न कर सकते हैं जो संकलन नहीं करते हैं। आपने एक ऐसी अभिव्यक्ति उत्पन्न की जो एक मुक्त चर का संदर्भ देती है fooजो मौजूद नहीं है? कठिन भाग्य, आप केवल यह देखेंगे कि जब वास्तव में आपके कोड जनरेटर का उपयोग किया जाता है, और केवल उन परिस्थितियों के तहत जो उस विशेष कोड की पीढ़ी को ट्रिगर करते हैं। यह इकाई परीक्षण के लिए भी बहुत मुश्किल है।

यह भी खतरनाक है:

  • कोड जो संकलन-समय पर चलता है, वह मनमानी कर सकता है IO, जिसमें मिसाइलों को लॉन्च करना या आपका क्रेडिट कार्ड चोरी करना शामिल है। आप कभी नहीं हर कार पैकेज के माध्यम से देखना चाहते हैं कि आप TH कारनामों के लिए खोज में डाउनलोड करें।
  • TH "मॉड्यूल-प्राइवेट" फ़ंक्शन और परिभाषाओं तक पहुंच सकता है, कुछ मामलों में पूरी तरह से इनकैप्सुलेशन को तोड़ सकता है।

फिर कुछ समस्याएं हैं जो लाइब्रेरी डेवलपर के रूप में उपयोग करने के लिए TH फ़ंक्शन को कम मज़ेदार बनाती हैं:

  • TH कोड हमेशा कंपोजेबल नहीं होता है। मान लीजिए कि कोई लेंस के लिए एक जनरेटर बनाता है, और अधिक बार नहीं, उस जनरेटर को इस तरह से संरचित किया जाएगा कि इसे केवल "एंड-यूज़र" द्वारा सीधे कॉल किया जा सकता है, न कि अन्य TH कोड द्वारा, उदाहरण के लिए पैरामीटर के रूप में लेंस उत्पन्न करने के लिए टाइप कंस्ट्रक्टर्स की एक सूची। कोड में उस सूची को उत्पन्न करना मुश्किल है, जबकि उपयोगकर्ता को केवल लिखना है generateLenses [''Foo, ''Bar]
  • डेवलपर्स भी नहीं जानते कि TH कोड की रचना की जा सकती है। क्या आप जानते हैं कि आप लिख सकते हैं forM_ [''Foo, ''Bar] generateLens? Qसिर्फ एक सनक है, इसलिए आप इस पर सभी सामान्य कार्यों का उपयोग कर सकते हैं। कुछ लोगों को यह पता नहीं है, और इस वजह से, वे एक ही कार्यशीलता के साथ अनिवार्य रूप से एक ही कार्य के कई अतिभारित संस्करण बनाते हैं, और ये फ़ंक्शन एक निश्चित ब्लोट प्रभाव को जन्म देते हैं। इसके अलावा, ज्यादातर लोग अपने जनरेटर को Qमोनाड में लिखते हैं, भले ही उनके पास न हो, जो लिखने जैसा है bla :: IO Int; bla = return 3; आप फ़ंक्शन को जरूरत से ज्यादा "पर्यावरण" दे रहे हैं, और फ़ंक्शन के ग्राहकों को उस प्रभाव के रूप में उस वातावरण को प्रदान करना आवश्यक है।

अंत में, कुछ चीजें हैं जो TH-end को अंतिम-उपयोगकर्ता के रूप में उपयोग करने के लिए कम मजेदार बनाती हैं:

  • अपारदर्शिता। जब एक TH फ़ंक्शन टाइप होता है Q Dec, तो यह मॉड्यूल के शीर्ष-स्तर पर बिल्कुल कुछ भी उत्पन्न कर सकता है, और आपके पास उत्पन्न होने वाले नियंत्रण पर बिल्कुल नियंत्रण नहीं होगा।
  • Monolithism। जब तक कि डेवलपर इसे अनुमति नहीं देता, तब तक आप यह नियंत्रित नहीं कर सकते कि यह कितना कार्य उत्पन्न करता है; यदि आपको एक फ़ंक्शन मिलता है जो एक डेटाबेस इंटरफ़ेस और एक JSON क्रमांकन इंटरफ़ेस उत्पन्न करता है , तो आप यह नहीं कह सकते हैं "नहीं, मैं केवल डेटाबेस इंटरफ़ेस चाहता हूं, धन्यवाद; मैं अपना खुद का JSON इंटरफ़ेस रोल करूंगा"
  • भागो समय। TH कोड को चलाने में अपेक्षाकृत लंबा समय लगता है। कोड को हर बार एक फ़ाइल संकलित किए जाने पर नए सिरे से व्याख्या की जाती है, और अक्सर, वें TH कोड द्वारा संकुल की एक टन की आवश्यकता होती है, जिसे लोड करना होता है। यह संकलन समय को काफी धीमा कर देता है।

4
इस तथ्य को जोड़ें कि टेम्पलेट-हैस्केल ऐतिहासिक रूप से बहुत खराब रूप से प्रलेखित किया गया है। (हालांकि मैं बस फिर से देखा और ऐसा लगता है कि चीजें कम से कम अब बेहतर हैं।) इसके अलावा, टेम्पलेट-हैस्केल को समझने के लिए, आपको अनिवार्य रूप से हास्केल भाषा के व्याकरण को समझना होगा, जो एक निश्चित मात्रा में जटिलता (यह कोई योजना नहीं है) को लागू करता है। जब मैंने हास्केल शुरुआत की थी, तब इन दो चीजों ने मुझे जानबूझकर परेशान नहीं किया।
११:४५ बजे माइटबाइट

14
मत भूलिए कि टेम्प्लेट हास्केल का उपयोग अचानक घोषणा के मामलों का क्रम है! TH सिर्फ इतना कसकर एकीकृत नहीं है जितना कि कोई हास्केल की चिकनी पॉलिश को दे सकता है (जैसा कि 1.4, '98, 2010 या यहां तक ​​कि ग्लासगो)।
थॉमस एम। डुबिसन

13
आप बहुत कठिनाई के बिना हास्केल के बारे में तर्क कर सकते हैं, खाका हास्केल के बारे में ऐसी कोई गारंटी नहीं है।
अगस्ता

15
और टीएच के एक प्रकार-सुरक्षित विकल्प के ओलेग के वादे का क्या हुआ? मैं उसकी के आधार पर अपने काम की चर्चा करते हुए कर रहा हूँ "अंत में tagless, आंशिक रूप से मूल्यांकन" कागज और उसकी नोटों की अधिक यहाँ । यह बहुत आशाजनक लग रहा था जब उन्होंने इसकी घोषणा की और फिर मैंने इसके बारे में एक और शब्द नहीं सुना।
गैब्रियल गोंजालेज


53

यह पूरी तरह से मेरी अपनी राय है।

  • इसका उपयोग करना बदसूरत है। $(fooBar ''Asdf)बस अच्छा नहीं लगता। सतही, सुनिश्चित, लेकिन यह योगदान देता है।

  • यह लिखना भी बदसूरत है। क्वोटिंग कभी-कभी काम करता है, लेकिन बहुत बार आपको मैनुअल एएसटी ग्राफ्टिंग और प्लंबिंग करना पड़ता है। एपीआई , बड़े और बोझल है वहाँ हमेशा मामलों आप के बारे में परवाह नहीं है, लेकिन अभी भी प्रेषण करने की जरूरत है की एक बहुत कुछ है, और मामलों आप देखभाल करने के बारे में कई समान है लेकिन समान नहीं रूपों में मौजूद हो जाते हैं (डेटा बनाम newtype, रिकॉर्ड -स्टाइल बनाम सामान्य निर्माता, और इसी तरह)। यह लिखने के लिए उबाऊ और दोहराव है और यांत्रिक नहीं होने के लिए पर्याप्त जटिल है। सुधार प्रस्ताव पते इस में से कुछ (उद्धरण अधिक व्यापक रूप से लागू कर रही है)।

  • चरण प्रतिबंध नरक है। एक ही मॉड्यूल में परिभाषित कार्यों को विभाजित करने में सक्षम नहीं होना इसका एक छोटा हिस्सा है: दूसरा परिणाम यह है कि यदि आपके पास एक शीर्ष-स्तरीय विभाजन है, तो मॉड्यूल में इसके बाद की हर चीज इसके दायरे से बाहर हो जाएगी। इस संपत्ति के साथ अन्य भाषाएं (C, C ++) आपको चीजों को अग्रेषित करने की अनुमति देकर इसे काम करने योग्य बनाती हैं, लेकिन हास्केल नहीं करता है। यदि आपको spliced ​​घोषणाओं या उनकी निर्भरता और आश्रितों के बीच चक्रीय संदर्भों की आवश्यकता है, तो आप आमतौर पर केवल खराब कर दिए जाते हैं।

  • यह अनुशासनहीन है। इससे मेरा तात्पर्य यह है कि जब आप अमूर्तता व्यक्त करते हैं, तो उस अमूर्त के पीछे किसी तरह का सिद्धांत या अवधारणा होती है। कई सार के लिए, उनके पीछे के सिद्धांत को उनके प्रकारों में व्यक्त किया जा सकता है। प्रकार की कक्षाओं के लिए, आप अक्सर कानून बना सकते हैं जो उदाहरणों का पालन करना चाहिए और ग्राहक मान सकते हैं। यदि आप किसी भी डेटाटाइप (सीमा के भीतर) पर उदाहरण की घोषणा के रूप को संक्षिप्त करने के लिए जीएचसी की नई जेनरिक सुविधा का उपयोग करते हैं , तो आपको "योग प्रकारों के लिए, यह इस तरह काम करता है, उत्पाद प्रकारों के लिए, यह उस तरह काम करता है"। दूसरी ओर टेम्पलेट हास्केल, केवल मैक्रोज़ है। यह विचारों के स्तर पर अमूर्त नहीं है, लेकिन एएसटी के स्तर पर अमूर्तता है, जो कि बेहतर है, लेकिन केवल मामूली पाठ के स्तर पर अमूर्तता की तुलना में मामूली है। *

  • यह आपको जीएचसी से जोड़ता है। सिद्धांत रूप में एक और संकलक इसे लागू कर सकता है, लेकिन व्यवहार में मुझे संदेह है कि यह कभी भी होगा। (यह विभिन्न प्रकार के सिस्टम एक्सटेंशनों के विपरीत है, जो कि वर्तमान में केवल जीएचसी द्वारा लागू किए जा सकते हैं, मैं आसानी से सड़क के नीचे अन्य कंपाइलरों द्वारा अपनाए जाने की कल्पना कर सकता हूं और अंततः मानकीकृत हो सकता हूं।)

  • एपीआई स्थिर नहीं है। जब GHC में नई भाषा सुविधाएँ जोड़ी जाती हैं और उनका समर्थन करने के लिए टेम्प्लेट-हैस्केल पैकेज अपडेट किया जाता है, तो इसमें अक्सर TH डेटाैटिप्स में पीछे-असंगत परिवर्तन शामिल होते हैं। यदि आप चाहते हैं कि आपका TH कोड GHC के सिर्फ एक से अधिक संस्करण के साथ संगत हो, तो आपको बहुत सावधान रहने और संभवतः उपयोग करने की आवश्यकता है CPP

  • एक सामान्य सिद्धांत यह है कि आपको नौकरी के लिए सही उपकरण का उपयोग करना चाहिए और सबसे छोटा जो कि पर्याप्त होगा, और उस सादृश्य टेम्पलेट हास्केल में ऐसा कुछ है । यदि ऐसा करने का कोई तरीका है जो टेम्पलेट हास्केल नहीं है, तो यह आमतौर पर बेहतर होता है।

टेम्पलेट हास्केल का लाभ यह है कि आप इसके साथ ऐसी चीजें कर सकते हैं जो आप किसी अन्य तरीके से नहीं कर सकते हैं, और यह एक बड़ा है। TH के लिए जिन चीजों का उपयोग किया जाता है उनमें से अधिकांश का उपयोग केवल तभी किया जा सकता है जब उन्हें सीधे संकलक सुविधाओं के रूप में लागू किया गया हो। TH दोनों के लिए बेहद फायदेमंद है क्योंकि यह आपको इन चीजों को करने देता है, और क्योंकि यह आपको अधिक हल्के और पुन: प्रयोज्य तरीके से संभावित कंपाइलर एक्सटेंशन को प्रोटोटाइप करने देता है (उदाहरण के लिए, विभिन्न लेंस पैकेज देखें)।

यह समझने के लिए कि मुझे क्यों लगता है कि टेम्पलेट हास्केल के प्रति नकारात्मक भावनाएं हैं: यह बहुत सारी समस्याओं को हल करता है, लेकिन किसी भी समस्या के लिए जो इसे हल करती है, उसे लगता है कि उस समस्या को हल करने के लिए बेहतर, अधिक सुरुचिपूर्ण, अनुशासित समाधान बेहतर होना चाहिए। जिनमें से एक समस्या का समाधान नहीं होता है स्वचालित रूप से बॉयलरप्लेट उत्पन्न करके, लेकिन करने की जरूरत को हटाने के द्वारा है बॉयलरप्लेट।

* हालांकि मुझे अक्सर लगता है कि CPPउन समस्याओं के लिए बेहतर शक्ति-से-वजन अनुपात है जो इसे हल कर सकते हैं।

संपादित करें 23-04-14: जो मैं अक्सर ऊपर में प्राप्त करने की कोशिश कर रहा था, और हाल ही में बिल्कुल प्राप्त किया है, वह यह है कि अमूर्तता और समर्पण के बीच एक महत्वपूर्ण अंतर है। उचित अमूर्तता अक्सर साइड इफेक्ट के रूप में समर्पण का परिणाम है, और दोहराव अक्सर अक्सर अपर्याप्त अमूर्त का एक गप्पी संकेत है, लेकिन यही कारण है कि यह मूल्यवान नहीं है। उचित अमूर्तता वह है जो कोड को सही, समझने योग्य और बनाए रखने योग्य बनाती है। Deduplication केवल इसे छोटा बनाता है। टेम्पलेट हास्केल, सामान्य रूप से मैक्रोज़ की तरह, समर्पण के लिए एक उपकरण है।


"सीपीपी के पास उन समस्याओं के लिए बेहतर शक्ति-से-भार अनुपात है जो इसे हल कर सकते हैं"। वास्तव में। और C99 में इसे आप जो चाहें हल कर सकते हैं। इन पर विचार करें: COS , अराजकता । मैं यह भी नहीं समझता कि लोग क्यों सोचते हैं कि एएसटी पीढ़ी बेहतर है। यह अन्य भाषाओं की विशेषताओं के लिए सिर्फ अधिक अस्पष्टता और कम ओर्थोगोनल है
ब्रिटन केरीन

31

मैं कुछ बिंदुओं को संबोधित करना चाहूंगा जिसमें dflemstr लाता है।

मुझे इस बात का पता नहीं है कि आप TH को उस चिंता का विषय नहीं बना सकते। क्यों? क्योंकि अगर कोई त्रुटि है, तो भी यह संकलन समय होगा। मुझे यकीन नहीं है कि यह मेरे तर्क को मजबूत करता है, लेकिन यह सी ++ में टेम्प्लेट का उपयोग करते समय आपको प्राप्त होने वाली त्रुटियों के समान है। मुझे लगता है कि ये त्रुटियां C ++ की त्रुटियों की तुलना में अधिक समझ में आती हैं, क्योंकि आपको उत्पन्न कोड का एक सुंदर मुद्रित संस्करण मिलेगा।

यदि कोई TH अभिव्यक्ति / अर्ध-उद्धरण ऐसा कुछ करता है जो इतना उन्नत है कि मुश्किल कोनों को छिपा सकता है, तो शायद यह गलत सलाह है?

मैं इस नियम को काफी हद तक क्वैसी-कोटर्स के साथ तोड़ता हूं जो मैं हाल ही में काम कर रहा हूं (हैस्केल-एसकेएक्स-एक्सटीएस / मेटा का उपयोग करके) - https://github.com/mgsloan/quasi-extras/tree/master/examples । मुझे पता है कि यह कुछ कीड़े का परिचय देता है जैसे कि सामान्यीकृत सूची की समझ में विभाजन करने में सक्षम नहीं है। हालाँकि, मुझे लगता है कि एक अच्छा मौका है कि http://hackage.haskell.org/trac/ghc/blog/Template%20Haskell%20Proposal में कुछ विचार संकलक में समाप्त हो जाएंगे। तब तक, हास्केल को TH पेड़ों को पार्स करने के लिए पुस्तकालय लगभग पूर्ण सन्निकटन हैं।

संकलन गति / निर्भरता के बारे में, हम उत्पन्न कोड को इनलाइन करने के लिए "शून्य" पैकेज का उपयोग कर सकते हैं। यह किसी दिए गए पुस्तकालय के उपयोगकर्ताओं के लिए कम से कम अच्छा है, लेकिन हम पुस्तकालय के संपादन के मामले में बहुत बेहतर नहीं कर सकते हैं। क्या टीएच निर्भरताएं उत्पन्न बायनेरिज़ को प्रफुल्लित कर सकती हैं? मैंने सोचा कि यह सब कुछ छोड़ दिया है जो संकलित कोड द्वारा संदर्भित नहीं है।

हास्केल मॉड्यूल के संकलन चरणों के मंचन / विभाजन को चूसना है।

RE अपारदर्शिता: आपके द्वारा कॉल किए गए किसी भी लाइब्रेरी फ़ंक्शन के लिए यह समान है। Data.List.groupBy क्या करेगा पर आपका कोई नियंत्रण नहीं है। आपके पास बस एक उचित "गारंटी" / सम्मेलन है कि संस्करण संख्या आपको संगतता के बारे में कुछ बताती है। यह परिवर्तन का एक अलग मामला है जब।

यह वह जगह है जहां शून्य का उपयोग करना बंद हो जाता है - आप पहले से ही उत्पन्न फ़ाइलों को संस्करणबद्ध कर रहे हैं - इसलिए आपको हमेशा पता चलेगा कि उत्पन्न कोड का रूप कब बदल गया है। डिफरेंशियल को देखते हुए, बड़ी मात्रा में जेनरेट किए गए कोड के लिए, हालांकि यह एक जगह है, जहां एक बेहतर डेवलपर इंटरफ़ेस काम करेगा।

आरई मोनोलिथिज्म: आप निश्चित रूप से अपने स्वयं के संकलन-समय कोड का उपयोग करके एक TH अभिव्यक्ति के परिणामों को पोस्ट-प्रोसेस कर सकते हैं। यह शीर्ष-स्तरीय घोषणा प्रकार / नाम को फ़िल्टर करने के लिए बहुत अधिक कोड नहीं होगा। हेक, आप एक फ़ंक्शन लिखने की कल्पना कर सकते हैं जो यह उदारतापूर्वक करता है। क्विज़िकोटर्स को संशोधित / de-monolithisizing करने के लिए, आप "QuasiQuoter" पर मिलान कर सकते हैं और उपयोग किए गए परिवर्तनों को निकाल सकते हैं, या पुराने के संदर्भ में एक नया बना सकते हैं।


1
अपारदर्शिता / अखंडता के बारे में : आप निश्चित रूप से एक के माध्यम से चल सकते हैं [Dec]और वह सामान निकाल सकते हैं जो आप नहीं चाहते हैं, लेकिन मान लें कि फ़ंक्शन JSON इंटरफ़ेस उत्पन्न करते समय एक बाहरी परिभाषा फ़ाइल पढ़ता है। सिर्फ इसलिए कि आप उपयोग नहीं करते Decहैं जो जनरेटर को परिभाषा फ़ाइल की तलाश नहीं करता है, जिससे संकलन विफल हो जाता है। उस कारण के लिए, यह अच्छा होगा Qकि आप उस नए नाम (और ऐसी चीजें) उत्पन्न करने दें IO, लेकिन अनुमति नहीं देते हैं , ताकि आप जैसा कहें, उसके परिणामों को फ़िल्टर कर सकें / अन्य रचनाएं कर सकें। ।
dflemstr

1
मैं सहमत हूं, क्यू / उद्धरण का एक गैर-आईओ संस्करण होना चाहिए! इससे हल करने में भी मदद मिलेगी - stackoverflow.com/questions/7107308/… । एक बार जब आप यह सुनिश्चित कर लेते हैं कि संकलन-समय कोड कुछ भी असुरक्षित नहीं करता है, तो ऐसा लगता है जैसे आप परिणामी कोड पर सुरक्षा चेकर को चला सकते हैं, और सुनिश्चित करें कि यह निजी सामान का संदर्भ नहीं देता है।
मगलून

1
क्या आपने कभी अपना प्रतिवाद लिखा? फिर भी आपके दिए गए लिंक का इंतज़ार रहेगा। इस उत्तर की पुरानी सामग्री की तलाश करने वालों के लिए: stackoverflow.com/revisions/10859441/1 , और उन लोगों के लिए जो हटाई गई सामग्री देख सकते हैं: stackoverflow.com/revisions/10913718/6
Dan Burton

1
क्या हैकरेज की तुलना में ज़रोथ का अधिक अद्यतित संस्करण है? उस एक (और डार्क्स रेपो) को आखिरी बार 2009 में अपडेट किया गया था। दोनों प्रतियां वर्तमान ghc (7.6) के साथ नहीं बनती हैं।
aavogt

1
@aavogt tgeeky इसे ठीक करने पर काम कर रहा था, लेकिन मुझे नहीं लगता कि उसने समाप्त किया: github.com/technogeeky/zeroth यदि कोई ऐसा नहीं करता है / इसके लिए कुछ बनाता है, तो मैं इसे अंततः प्राप्त करूँगा।
मग्लोसन

16

यह जवाब इलिस्सियस द्वारा उठाए गए मुद्दों के जवाब में है, बिंदु द्वारा बिंदु:

  • इसका उपयोग करना बदसूरत है। $ (fooBar '' Asdf) बस अच्छा नहीं लगता। सतही, सुनिश्चित, लेकिन यह योगदान देता है।

मैं सहमत हूँ। मुझे ऐसा लग रहा है कि $ () देखने के लिए चुना गया था क्योंकि यह भाषा का हिस्सा था - हास्केल के परिचित प्रतीक फूस का उपयोग करके। हालाँकि, यह वही है जो आप अपने मैक्रो स्प्लिसिंग के लिए उपयोग किए जाने वाले प्रतीकों में / नहीं / चाहते हैं। वे निश्चित रूप से बहुत अधिक मात्रा में मिश्रण करते हैं, और यह कॉस्मेटिक पहलू काफी महत्वपूर्ण है। मुझे स्पिलेस के लिए {{}} का लुक पसंद है, क्योंकि वे काफी नेत्रहीन हैं।

  • यह लिखना भी बदसूरत है। क्वोटिंग कभी-कभी काम करता है, लेकिन बहुत बार आपको मैनुअल एएसटी ग्राफ्टिंग और प्लंबिंग करना पड़ता है। [एपीआई] [१] बड़ा और अलौकिक है, ऐसे बहुत से मामले हैं जिनकी आपको परवाह नहीं है, लेकिन फिर भी उन्हें प्रेषण करने की आवश्यकता है, और जिन मामलों की आप परवाह करते हैं, वे कई समान हैं, लेकिन समान रूपों में मौजूद नहीं हैं (डेटा बनाम न्यूटाइप, रिकॉर्ड-स्टाइल बनाम सामान्य कंस्ट्रक्टर, और इसी तरह)। यह लिखने के लिए उबाऊ और दोहराव है और यांत्रिक नहीं होने के लिए पर्याप्त जटिल है। [सुधार प्रस्ताव] [2] इसमें से कुछ को संबोधित करते हैं (उद्धरण को अधिक व्यापक रूप से लागू करते हैं)।

मैं इस बात से भी सहमत हूं, हालांकि, "टीएच के लिए नई दिशाएं" टिप्पणियों में से कुछ के रूप में, अच्छा आउट-ऑफ-द-बॉक्स एएसटी उद्धरण की कमी एक महत्वपूर्ण दोष नहीं है। इस WIP पैकेज में, मैं इन समस्याओं को लाइब्रेरी रूप में संबोधित करना चाहता हूं: https://github.com/mgsloan/quasi-extras । अब तक मैं सामान्य से कुछ अधिक स्थानों पर स्प्लिसिंग की अनुमति देता हूं और एएसटीएस पर मैच कर सकता हूं।

  • चरण प्रतिबंध नरक है। एक ही मॉड्यूल में परिभाषित कार्यों को विभाजित करने में सक्षम नहीं होना इसका एक छोटा हिस्सा है: दूसरा परिणाम यह है कि यदि आपके पास एक शीर्ष-स्तरीय विभाजन है, तो मॉड्यूल में इसके बाद की हर चीज इसके दायरे से बाहर हो जाएगी। इस संपत्ति के साथ अन्य भाषाएं (C, C ++) आपको चीजों को अग्रेषित करने की अनुमति देकर इसे काम करने योग्य बनाती हैं, लेकिन हास्केल नहीं करता है। यदि आपको spliced ​​घोषणाओं या उनकी निर्भरता और आश्रितों के बीच चक्रीय संदर्भों की आवश्यकता है, तो आप आमतौर पर केवल खराब कर दिए जाते हैं।

मैं चक्रीय टीएच परिभाषाओं के मुद्दे पर पहले भी असंभव रहा हूं ... यह काफी कष्टप्रद है। एक समाधान है, लेकिन यह बदसूरत है - एक TH अभिव्यक्ति में चक्रीय निर्भरता में शामिल चीजों को लपेटें जो सभी उत्पन्न घोषणाओं को जोड़ती है। इन घोषणाओं में से एक जनरेटर सिर्फ एक अर्ध-उद्धरण हो सकता है जो हास्केल कोड को स्वीकार करता है।

  • यह अपूर्व है। इससे मेरा अभिप्राय यह है कि जब आप अमूर्त को व्यक्त करते हैं, तो उस अमूर्त के पीछे किसी प्रकार का सिद्धांत या अवधारणा होती है। कई सार के लिए, उनके पीछे के सिद्धांत को उनके प्रकारों में व्यक्त किया जा सकता है। जब आप एक प्रकार की कक्षा को परिभाषित करते हैं, तो आप अक्सर कानून बना सकते हैं जो उदाहरणों का पालन करना चाहिए और ग्राहक मान सकते हैं। यदि आप GHC की [नई जेनरिक विशेषता] का उपयोग करते हैं [3] तो किसी भी डेटाटाइप (सीमा के भीतर) पर एक उदाहरण घोषणा के रूप को सार करने के लिए, आपको "प्रकारों के लिए" कहना होगा, यह इस तरह से काम करता है, उत्पाद प्रकारों के लिए, यह उस तरह से काम करता है "। लेकिन टेम्पलेट हास्केल सिर्फ गूंगा मैक्रोज़ है। यह विचारों के स्तर पर अमूर्त नहीं है, लेकिन एएसटी के स्तर पर अमूर्तता, जो कि बेहतर है, लेकिन केवल मामूली पाठ के स्तर पर अमूर्तता से बेहतर है।

यदि आप इसके साथ अप्रत्याशित चीजें करते हैं तो यह केवल अप्रत्याशित है। अंतर केवल इतना है कि संकलक के लिए संकलक कार्यान्वित तंत्र के साथ, आपको अधिक विश्वास है कि अमूर्त रिसाव नहीं है। शायद लोकतांत्रिक भाषा डिजाइन थोड़ा डरावना लगता है! TH पुस्तकालयों के रचनाकारों को अच्छी तरह से दस्तावेज़ बनाने और उनके द्वारा प्रदान किए जाने वाले उपकरणों के अर्थ और परिणामों को स्पष्ट रूप से परिभाषित करने की आवश्यकता है। प्रिंसिपल TH का एक अच्छा उदाहरण व्युत्पन्न पैकेज है: http://hackage.haskell.org/package/derive - यह एक DSL का उपयोग करता है जैसे कि व्युत्पन्न / निर्दिष्ट / वास्तविक व्युत्पत्ति में से कई का उदाहरण।

  • यह आपको जीएचसी से जोड़ता है। सिद्धांत रूप में एक और संकलक इसे लागू कर सकता है, लेकिन व्यवहार में मुझे संदेह है कि यह कभी भी होगा। (यह विभिन्न प्रकार के सिस्टम एक्सटेंशनों के विपरीत है, जो कि वर्तमान में केवल जीएचसी द्वारा लागू किए जा सकते हैं, मैं आसानी से सड़क के नीचे अन्य कंपाइलरों द्वारा अपनाए जाने की कल्पना कर सकता हूं और अंततः मानकीकृत हो सकता हूं।)

यह एक बहुत अच्छा बिंदु है - TH एपीआई बहुत बड़ा और स्पष्ट है। इसे फिर से लागू करना ऐसा लगता है कि यह कठिन हो सकता है। हालांकि, हास्केल एएसटीएस का प्रतिनिधित्व करने की समस्या को समाप्त करने के केवल कुछ ही तरीके हैं। मुझे लगता है कि TH ADTs की प्रतिलिपि बनाना, और आंतरिक एएसटी प्रतिनिधित्व के लिए एक कनवर्टर लिखना आपको वहां के तरीके का एक अच्छा सौदा मिलेगा। यह haskell-src-meta बनाने के (तुच्छ नहीं) प्रयास के बराबर होगा। यह केवल TH AST को सुंदर रूप से प्रिंट करके और संकलक के आंतरिक पार्सर का उपयोग करके फिर से लागू किया जा सकता है।

जबकि मैं गलत हो सकता है, मैं TH को एक कार्यान्वयन दृष्टिकोण के आधार पर एक कंपाइलर एक्सटेंशन के जटिल होने के रूप में नहीं देखता हूं। यह वास्तव में "इसे सरल रखने" के लाभों में से एक है और मौलिक परत न होने पर कुछ सैद्धांतिक रूप से आकर्षक, वैधानिक रूप से सत्यापित करने वाली प्रणाली है।

  • एपीआई स्थिर नहीं है। जब GHC में नई भाषा सुविधाएँ जोड़ी जाती हैं और उनका समर्थन करने के लिए टेम्प्लेट-हैस्केल पैकेज अपडेट किया जाता है, तो इसमें अक्सर TH डेटाैटिप्स में पीछे-असंगत परिवर्तन शामिल होते हैं। यदि आप चाहते हैं कि आपका TH कोड GHC के सिर्फ एक से अधिक संस्करण के साथ संगत हो, तो आपको बहुत सावधान रहने और संभवतः उपयोग करने की आवश्यकता है CPP

यह भी एक अच्छी बात है, लेकिन कुछ हद तक नाटकीय है। जबकि वहाँ हाल ही में एपीआई परिवर्धन किया गया है, वे बड़े पैमाने पर टूटने उत्प्रेरण नहीं किया गया है। इसके अलावा, मुझे लगता है कि मैंने पहले उल्लेख किए गए बेहतर एएसटी उद्धरण के साथ, एपीआई जिसे वास्तव में उपयोग करने की आवश्यकता है, उसे बहुत कम किया जा सकता है। यदि किसी निर्माण / मिलान के लिए अलग-अलग कार्यों की आवश्यकता होती है, और इसके बजाय उन्हें शाब्दिक रूप में व्यक्त किया जाता है, तो अधिकांश एपीआई गायब हो जाते हैं। इसके अलावा, आपके द्वारा लिखा गया कोड Haskell जैसी भाषाओं के लिए AST अभ्यावेदन के लिए अधिक आसानी से पोर्ट करेगा।


सारांश में, मुझे लगता है कि TH एक शक्तिशाली, अर्ध-उपेक्षित उपकरण है। कम घृणा पुस्तकालयों के अधिक जीवंत इको-सिस्टम को जन्म दे सकती है, जो अधिक भाषा सुविधा प्रोटोटाइप के कार्यान्वयन को प्रोत्साहित करती है। यह देखा गया है कि TH एक अधिकता वाला उपकरण है, जो आपको कुछ भी कर सकता है / कर सकता है। अराजकता! खैर, यह मेरी राय है कि यह शक्ति आपको इसकी अधिकांश सीमाओं को पार करने की अनुमति दे सकती है, और काफी राजसी मेटा-प्रोग्रामिंग दृष्टिकोणों में सक्षम सिस्टम का निर्माण कर सकती है। यह "उचित" कार्यान्वयन को अनुकरण करने के लिए बदसूरत हैक्स के उपयोग के लायक है, क्योंकि इस तरह "उचित" कार्यान्वयन का डिज़ाइन धीरे-धीरे स्पष्ट होगा।

निर्वाण के मेरे व्यक्तिगत आदर्श संस्करण में, भाषा का अधिकांश भाग वास्तव में संकलक से हटकर, इन विविधता के पुस्तकालयों में होगा। तथ्य यह है कि सुविधाओं को पुस्तकालयों के रूप में लागू किया जाता है, उनकी क्षमता को विश्वासपूर्वक अमूर्त करने के लिए बहुत अधिक प्रभावित नहीं करता है।

बॉयलरप्लेट कोड के लिए विशिष्ट हास्केल उत्तर क्या है? अमूर्त। हमारे पसंदीदा सार क्या हैं? फ़ंक्शंस और टाइपकास्ट!

टाइपकास्ट हमें विधियों का एक सेट परिभाषित करते हैं, जो तब उस वर्ग पर सभी प्रकार के फ़ंक्शन जेनेरिक में उपयोग किए जा सकते हैं। हालांकि, इसके अलावा, एकमात्र तरीका कक्षाएं बॉयलरप्लेट से बचने में मदद करता है "डिफ़ॉल्ट परिभाषा" की पेशकश करके। अब यहाँ एक अप्रत्याशित सुविधा का एक उदाहरण है!

  • न्यूनतम बाध्यकारी सेट घोषित / संकलक चेक करने योग्य नहीं हैं। इससे अनजानी परिभाषाएं हो सकती हैं जो पारस्परिक पुनरावृत्ति के कारण नीचे की उपज होती हैं।

  • महान सुविधा और शक्ति के बावजूद यह उपज देगा, आप अनाथ दोषों को निर्दिष्ट नहीं कर सकते, अनाथ उदाहरणों के कारण http://lukepalmer.wordpress.com/2009/01/25/a-world-without-orphans/ ये हमें ठीक कर देंगे सांख्यिक पदानुक्रम सुशोभित!

  • THa जैसी क्षमताओं के बाद विधि चूक के लिए जा रहे http://www.haskell.org/haskellwiki/GHC.Generics । हालांकि यह शांत सामान है, इन जेनरिक का उपयोग करने वाला मेरा एकमात्र अनुभव डिबगिंग कोड शून्य-असंभव था, एएसटी के रूप में और एडीटी के लिए प्रेरित प्रकार के आकार के कारण। https://github.com/mgsloan/th-extra/commit/d7784d95d396eb3abdb409a24360beb03731c88c

    दूसरे शब्दों में, यह TH द्वारा प्रदान की गई सुविधाओं के बाद चला गया, लेकिन इसे भाषा के एक संपूर्ण डोमेन, निर्माण भाषा को एक प्रकार के सिस्टम प्रतिनिधित्व में उठाना पड़ा। जबकि मैं इसे आपकी सामान्य समस्या के लिए अच्छी तरह से काम करते हुए देख सकता हूं, जटिल लोगों के लिए, यह TH हैकरी की तुलना में कहीं अधिक भयानक प्रतीकों के ढेर से ग्रस्त होने का खतरा है।

    TH आपको आउटपुट कोड के मूल्य-स्तरीय संकलन-समय की गणना देता है, जबकि जेनरिक आपको कोड के पैटर्न मिलान / पुनरावृत्ति भाग को टाइप सिस्टम में उठाने के लिए मजबूर करता है। हालांकि यह उपयोगकर्ता को कुछ उपयोगी तरीकों से प्रतिबंधित करता है, मुझे नहीं लगता कि जटिलता इसके लायक है।

मुझे लगता है कि टीएच और लिस्प की तरह मेटाप्रोग्रामिंग की अस्वीकृति ने अधिक लचीले, स्थूल-विस्तार जैसे उदाहरणों की घोषणाओं के बजाय पद्धति-चूक जैसी चीजों को वरीयता दी। उन चीजों से बचने का अनुशासन जो अप्रत्याशित परिणाम पैदा कर सकते हैं, बुद्धिमान हैं, हालांकि, हमें यह ध्यान नहीं देना चाहिए कि हास्केल की सक्षम प्रकार प्रणाली कई अन्य वातावरणों (उत्पन्न कोड की जांच करके) की तुलना में अधिक विश्वसनीय मेटाप्रोग्रामिंग की अनुमति देती है।


4
यह उत्तर बहुत अच्छी तरह से अपने आप नहीं खड़ा होता है: आप किसी अन्य उत्तर के संदर्भों का एक गुच्छा बना रहे हैं, जो मुझे आपके ठीक से पढ़ने से पहले जाना और ढूंढना होगा।
बेन मिलवुड

यह सच है। मैंने यह स्पष्ट करने की कोशिश की कि किसके बावजूद बात की जा रही है। शायद मैं इनलाइन इलिसिंस के बिंदुओं को संपादित करूंगा।
मगलून

मुझे यह कहना चाहिए कि शायद "अप्रतिष्ठित" एक मजबूत शब्द है जिसका मुझे उपयोग करना चाहिए था, कुछ अनुमानों के साथ जो मैंने इरादा नहीं किया था - यह निश्चित रूप से बेईमान नहीं है! वह बुलेट पॉइंट वह था जिसकी मुझे सबसे अधिक परेशानी थी, क्योंकि मेरे दिमाग में यह भावना या विकृत विचार है और इसे शब्दों में रखने में परेशानी होती है, और "अप्रत्याशित" मैं उन शब्दों में से एक था जिसे मैंने समझ लिया था जो कहीं न कहीं आसपास था। "अनुशासित" शायद करीब है। एक स्पष्ट और संक्षिप्त रूप नहीं होने के कारण मैं इसके बजाय कुछ उदाहरणों के लिए गया। अगर कोई मुझे अधिक स्पष्ट रूप से समझा सकता है कि मेरा क्या मतलब है, तो मैं इसकी सराहना करूंगा!
glaebhoerl

(इसके अलावा मुझे लगता है कि आपने स्टेजिंग प्रतिबंध और बदसूरत लिखने के उद्धरणों को बदल दिया होगा।)
glaebhoerl

1
रवींद्र! यह बात बताने के लिए धन्यवाद! फिक्स्ड। हां, अनुशासनहीन इसे लगाने का बेहतर तरीका होगा। मुझे लगता है कि यहाँ अंतर "बिल्ट-इन" और वास्तव में "अच्छी तरह से समझा जाने वाला" एब्सट्रैक्शन मैकेनिज़्म, बनाम "एड-हॉक", या यूज़र-डिफ़ाइंड एब्सट्रैक्शन मैकेनिज़्म के बीच है। मुझे लगता है कि मेरा क्या मतलब है कि आप एक टीएच लाइब्रेरी को परिभाषित कर सकते हैं, जिसमें टाइपकास्टल डिस्पैच के समान कुछ लागू किया गया है (यद्यपि संकलन समय पर न होने पर भी)
मैग्लून

8

टेम्पलेट हास्केल के साथ एक बल्कि व्यावहारिक समस्या यह है कि यह केवल तभी काम करता है जब जीएचसी का बायटेकोड दुभाषिया उपलब्ध होता है, जो सभी आर्किटेक्चर पर ऐसा नहीं है। इसलिए यदि आपका प्रोग्राम टेम्पलेट हास्केल का उपयोग करता है या इसका उपयोग करने वाले पुस्तकालयों पर निर्भर करता है, तो यह एआरएम, एमआइपी, एस 390 या पावरपीसी सीपीयू के साथ मशीनों पर नहीं चलेगा।

यह व्यवहार में प्रासंगिक है: गिट-एनेक्स हास्केल में लिखा गया एक उपकरण है जो भंडारण के बारे में चिंता करने वाली मशीनों पर चलने के लिए समझ में आता है, ऐसी मशीनों में अक्सर गैर-आई 386-सीपीयू होते हैं। व्यक्तिगत रूप से, मैं एक NSLU 2 पर git- annex चलाता हूं (32 एमबी रैम, ; क्या आप जानते हैं कि हास्केल ऐसे हार्डवेयर पर ठीक काम करता है?) यदि यह टेम्पलेट हास्केल का उपयोग करेगा, तो यह संभव नहीं है।

(एआरएम पर जीएचसी के बारे में स्थिति इन दिनों बहुत सुधार कर रही है और मुझे लगता है कि 7.4.2 भी काम करता है, लेकिन बिंदु अभी भी खड़ा है)।


1
"टेम्प्लेट हास्केल, GHC के बिल्ट-इन बायटेकोड कंपाइलर और इंटरप्रिटर पर ब्याह के भावों को चलाने के लिए निर्भर करता है।" - haskell.org/ghc/docs/7.6.2/html/users_guide/…
जोकिम

2
आह, मैं कि - नहीं, TH बाईटेकोड दुभाषिया के बिना काम नहीं करेगा, लेकिन यह (हालांकि प्रासंगिक) gci से अलग है। मुझे आश्चर्य नहीं होगा अगर वहाँ ghci की उपलब्धता और bytecode दुभाषिया की उपलब्धता के बीच एक पूर्ण संबंध था, यह देखते हुए कि ghci bytecode दुभाषिया पर निर्भर करता है, लेकिन समस्या वहाँ bytecode दुभाषिया की कमी है, ghci की कमी नहीं है विशेष रूप से।
मुहमुह्तन

1
(संयोग से, ghci -XTemplateHaskell <<< '$(do Language.Haskell.TH.runIO $ (System.Random.randomIO :: IO Int) >>= print; [| 1 |] )'
Ghci

ठीक है, ghci के साथ मैं GHC की व्याख्या करने के लिए (संकलन के बजाय) कोड की क्षमता का जिक्र कर रहा था, इस बात से स्वतंत्र कि क्या कोड ghci बाइनरी में इंटरएक्टिवली आता है, या TH ब्याह से।
जोकिम ब्रेटनर

6

क्यों बुरा है? मेरे लिए, यह नीचे आता है:

यदि आपको इतने दोहराव वाले कोड का उत्पादन करने की आवश्यकता है, जो आपको लगता है कि TH को ऑटो-जेनरेट करने के लिए उपयोग करने की कोशिश कर रहे हैं , तो आप इसे गलत कर रहे हैं!

इसके बारे में सोचो। हास्केल की आधी अपील यह है कि इसका उच्च-स्तरीय डिज़ाइन आपको भारी मात्रा में बॉयलरप्लेट कोड से बचने की अनुमति देता है जिसे आपको अन्य भाषाओं में लिखना होगा। अगर आपको जरूरत है कोड पीढ़ी समय संकलन, आप मूल रूप से कह रहे हैं कि या तो अपनी भाषा या अपने आवेदन डिजाइन आप नाकाम रही है। और हम प्रोग्रामर विफल होना पसंद नहीं करते।

कभी-कभी, ज़ाहिर है, यह आवश्यक है। लेकिन कभी-कभी आप अपने डिजाइनों के साथ थोड़ा अधिक चतुर होने से TH की आवश्यकता से बच सकते हैं।

(दूसरी बात यह है कि TH काफी निम्न-स्तर है। कोई भव्य उच्च-स्तरीय डिज़ाइन नहीं है; GHC के बहुत से आंतरिक विवरणों का खुलासा किया गया है। और यह एपीआई को बदलने की संभावना बनाता है ...)


मुझे नहीं लगता कि इसका मतलब यह है कि आपकी भाषा या एप्लिकेशन आपको विफल कर दिया है, खासकर अगर हम QuasiQuotes पर विचार करते हैं। सिंटैक्स की बात आती है तो हमेशा ट्रेड-ऑफ होते हैं। कुछ सिंटैक्स बेहतर डोमेन का वर्णन करते हैं, इसलिए आप कभी-कभी किसी अन्य सिंटैक्स पर स्विच करने में सक्षम होना चाहते हैं। QuasiQuotes आपको सिंटैक्स के बीच सुरुचिपूर्ण ढंग से स्विच करने की अनुमति देता है। यह बहुत शक्तिशाली है और इसका उपयोग Yesod और अन्य ऐप्स द्वारा किया जाता है। HTML की तरह लगता है कि सिंटैक्स का उपयोग करके HTML पीढ़ी कोड लिखने में सक्षम होने के नाते एक अद्भुत विशेषता है।
कूलकोडब्रो

@CoolCodeBro हाँ, अर्ध-उद्धरण काफी अच्छा है, और मुझे लगता है कि थोथे थोथोनल से टीएच। (जाहिर है कि इसे TH के शीर्ष पर लागू किया गया है।) मैं वर्ग उदाहरणों को उत्पन्न करने के लिए TH का उपयोग करने के बारे में अधिक सोच रहा था, या कई प्रकार के कार्यों का निर्माण, या ऐसा कुछ।
गणितीयऑक्रिड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.