C में कार्यात्मक प्रोग्रामिंग के लिए कौन से उपकरण हैं?


153

मैं हाल ही में बहुत सोच रहा हूं कि कैसे सी ( नहीं सी ++) में कार्यात्मक प्रोग्रामिंग करने के बारे में जाना जाए । जाहिर है, सी एक प्रक्रियात्मक भाषा है और वास्तव में कार्यात्मक प्रोग्रामिंग का समर्थन नहीं करती है।

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

उदाहरण के लिए, एक चीज जो मुझे लगता है कि सी में वास्तव में उपयोगी हो सकती है वह यह है कि कहीं भी एक फ़ंक्शन पॉइंटर की उम्मीद की जाती है, आप एक लंबर अभिव्यक्ति को पारित करने में सक्षम हो सकते हैं, एक क्लोजर बना सकते हैं जो फ़ंक्शन पॉइंटर में बदल जाता है। C ++ 0x में लैम्ब्डा एक्सप्रेशन (जो मुझे लगता है कि कमाल है) को शामिल करने जा रहा है; हालाँकि, मैं सी पर लागू उपकरणों की तलाश कर रहा हूँ।

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


1
हैक और गैर-पोर्टेबल एक्सटेंशन की तलाश में सी को कुछ में बदलने की कोशिश करने के बजाय, यह क्यों नहीं है, आप केवल उस भाषा का उपयोग नहीं करते हैं जो आपके लिए देख रहे हैं कार्यक्षमता प्रदान करता है?
रॉबर्ट गैंबल

संबंधित प्रश्न भी देखें: < stackoverflow.com/questions/24995/… >
एंडी ब्राइस

@AndyBrice यह सवाल एक अलग भाषा के बारे में है और यह वास्तव में समझ में नहीं आता है (C ++ में "पारिस्थितिकी तंत्र" समान अर्थों में नहीं है।
काइल स्ट्रैंड

जवाबों:


40

FFCALL आपको C में क्लोजर बनाने देता है - callback = alloc_callback(&function, data)एक फ़ंक्शन पॉइंटर ऐसे लौटाता है जो callback(arg1, ...)कॉल करने के बराबर है function(data, arg1, ...)। यद्यपि आपको मैन्युअल रूप से कचरा संग्रहण संभालना होगा।

संबंधित रूप से, Apple के GCC के फोर्क में ब्लॉक जोड़े गए हैं; वे फ़ंक्शन पॉइंटर्स नहीं हैं, लेकिन वे आपको हाथ से पकड़े गए चर के लिए निर्माण और मुफ्त भंडारण की आवश्यकता से बचने के दौरान लैम्बदास के चारों ओर से गुजरते हैं (प्रभावी रूप से, कुछ प्रतिलिपि और संदर्भ गिनती होती है, कुछ सिंटैक्टिक चीनी और रनटाइम लाइब्रेरी के पीछे छिपा हुआ है)।


89

आप लैम्ब्डा एक्सप्रेशन का अनुकरण करने के लिए GCC के नेस्टेड फ़ंक्शंस का उपयोग कर सकते हैं, वास्तव में, मेरे पास इसे करने के लिए एक मैक्रो है:

#define lambda(return_type, function_body) \
  ({ \
    return_type anon_func_name_ function_body \
    anon_func_name_; \
  })

इस तरह का उपयोग करें:

int (*max)(int, int) = lambda (int, (int x, int y) { return x > y ? x : y; });

12
यह वास्ताव में अच्छा है। ऐसा लगता __fn__है कि ब्लॉक के भीतर परिभाषित फ़ंक्शन के लिए केवल मनमाना नाम है ({... })कुछ जीसीसी विस्तार या पूर्वनिर्धारित मैक्रो नहीं? के लिए नाम की पसंद __fn__(बहुत जीसीसी परिभाषा की तरह लग रही है) ने वास्तव में मेरे सिर को खरोंच कर दिया और बिना किसी अच्छे प्रभाव के जीसीसी दस्तावेज की खोज की।
FooF

1
अफसोस की बात है, यह व्यवहार में काम नहीं करता है: यदि आप कुछ भी कैप्चर करने के लिए बंद करना चाहते हैं, तो इसके लिए एक निष्पादन योग्य स्टैक की आवश्यकता होती है, जो एक भयानक सुरक्षा अभ्यास है। व्यक्तिगत रूप से, मुझे नहीं लगता कि यह उपयोगी है।
डेमी

यह दूर से उपयोगी नहीं है, लेकिन यह मजेदार है। इसलिए दूसरा उत्तर स्वीकार किया जाता है।
जो डी

65

फ़ंक्शनल प्रोग्रामिंग लैम्ब्डा के बारे में नहीं है, यह सभी शुद्ध कार्यों के बारे में है। तो निम्नलिखित मोटे तौर पर कार्यात्मक शैली को बढ़ावा देते हैं:

  1. केवल फ़ंक्शन तर्कों का उपयोग करें, वैश्विक स्थिति का उपयोग न करें।

  2. साइड इफेक्ट्स यानी प्रिंटफ या किसी आईओ को कम से कम करें। सभी विवरणों में सीधे दुष्प्रभावों के कारण के बजाय निष्पादित किए जा सकने वाले IO का विवरण लौटाएं।

यह सादे सी में प्राप्त किया जा सकता है, जादू की कोई आवश्यकता नहीं है।


5
मुझे लगता है कि आपने कार्यात्मक प्रोग्रामिंग के उस चरम दृश्य को गैरबराबरी के बिंदु पर ले लिया है। क्या अच्छा है, इसका शुद्ध विनिर्देशन है, उदाहरण के लिए map, अगर किसी के पास इसके लिए एक समारोह पास करने की सुविधा नहीं है?
जोनाथन लियोनार्ड

27
मुझे लगता है कि यह दृष्टिकोण सी के अंदर एक कार्यात्मक भाषा बनाने के लिए मैक्रोज़ का उपयोग करने की तुलना में कहीं अधिक व्यावहारिक है। शुद्ध कार्यों का उपयोग उचित रूप से छोरों के बजाय नक्शे का उपयोग करने की तुलना में एक प्रणाली में सुधार करने की अधिक संभावना है।
एंडी

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

PS पिछला टिप्पणी मोबाइल से थी- अनियमित व्याकरण जानबूझकर नहीं था।
जोनाथन लियोनार्ड

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

17

हार्टेल और मुलर की पुस्तक, फंक्शनल सी , आजकल (2012-01-02) यहां पाई जा सकती है: http://eprints.eemcs.utwente.nl/1077/ (पीडीएफ संस्करण के लिए एक लिंक है)।


2
इस पुस्तक में कुछ भी कार्यात्मक नहीं है (जैसा कि प्रश्न से संबंधित है)।
यूजीन टॉल्मचेव

4
लगता है आप काफी सही हैं। दरअसल, प्रस्तावना में कहा गया है कि पुस्तक का उद्देश्य अनिवार्य प्रोग्रामिंग सिखाना है क्योंकि छात्र पहले से ही कार्यात्मक प्रोग्रामिंग से परिचित हो चुका है। FYI करें, यह SO में मेरा पहला उत्तर था और यह केवल एक उत्तर के रूप में लिखा गया था क्योंकि मुझे सड़े हुए लिंक के साथ पिछले उत्तर पर टिप्पणी करने के लिए प्रतिष्ठा की आवश्यकता नहीं थी। मुझे हमेशा आश्चर्य होता है कि लोग इस उत्तर को +1 क्यों रखते हैं ... कृपया ऐसा न करें! :-)
FooF

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

और यह एक डुप्लिकेट उत्तर है
PhilT

8

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

  • मैनुअल ऑफ़ लेक्सिकल स्कोप बाइंडिंग, उर्फ ​​क्लोजर।
  • समारोह चर के मैनुअल प्रबंधन जीवनकाल।
  • फ़ंक्शन एप्लिकेशन / कॉल का वैकल्पिक सिंटैक्स।
/* 
 * with constraints desribed above we could have
 * good approximation of FP style in plain C
 */

int increment_int(int x) {
  return x + 1;
}

WRAP_PLAIN_FUNCTION_TO_FIRST_CLASS(increment, increment_int);

map(increment, list(number(0), number(1)); // --> list(1, 2)


/* composition of first class function is also possible */

function_t* computation = compose(
  increment,
  increment,
  increment
);

*(int*) call(computation, number(1)) == 4;

ऐसे कोड के लिए रनटाइम नीचे के रूप में छोटा हो सकता है

struct list_t {
  void* head;
  struct list_t* tail;
};

struct function_t {
   void* (*thunk)(list_t*);
   struct list_t* arguments;
}

void* apply(struct function_t* fn, struct list_t* arguments) {
  return fn->thunk(concat(fn->arguments, arguments));
}

/* expansion of WRAP_PLAIN_FUNCTION_TO_FIRST_CLASS */
void* increment_thunk(struct list_t* arguments) {
  int x_arg = *(int*) arguments->head;
  int value = increment_int(x_arg);
  int* number = malloc(sizeof *number);

  return number ? (*number = value, number) : NULL;
}

struct function_t* increment = &(struct function_t) {
  increment_thunk,
  NULL
};

/* call(increment, number(1)) expands to */
apply(increment, &(struct list_t) { number(1), NULL });

संक्षेप में, हम मैक्रोसेस के फ़ंक्शन / तर्कों और गुच्छा के जोड़े के रूप में प्रतिनिधित्व किए गए क्लोजर के साथ प्रथम श्रेणी के फ़ंक्शन का अनुकरण करते हैं। पूरा कोड यहां पाया जा सकता है


7

मुख्य बात जो दिमाग में आती है वह है कोड जनरेटर का उपयोग। क्या आप एक अलग भाषा में प्रोग्राम करने के लिए तैयार होंगे जो कार्यात्मक प्रोग्रामिंग प्रदान करती है और फिर उससे सी कोड उत्पन्न करती है?

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

C निश्चित रूप से फ़ंक्शन पॉइंटर्स का उपयोग करते हुए फ़ंक्शन पास कर सकता है, मुख्य समस्याएं क्लोज़र की कमी हैं और टाइप सिस्टम रास्ते में प्राप्त करता है। आप सीपीपी की तुलना में अधिक शक्तिशाली मैक्रो सिस्टम का पता लगा सकते थे जैसे कि एम 4। मैं अंत में अनुमान लगाता हूं कि मैं जो सुझाव दे रहा हूं, वह यह है कि सही सी महान कार्य के बिना काम पर नहीं है, लेकिन आप सी को बढ़ा सकते हैं ताकि यह कार्य तक हो सके। यदि आप CPP का उपयोग करते हैं तो यह एक्सटेंशन C की तरह सबसे अधिक दिखाई देगा या आप स्पेक्ट्रम के दूसरे छोर पर जा सकते हैं और किसी अन्य भाषा से C कोड उत्पन्न कर सकते हैं।


यह सबसे ईमानदार जवाब है। सी को एक कार्यात्मक तरीके से लिखने की कोशिश करना भाषा की संरचना और संरचना के खिलाफ लड़ना है।
जोसिया

5

यदि आप क्लोजर लागू करना चाहते हैं, तो आपको असेंबली लैंग्वेज और स्टैक स्वैपिंग / मैनेजमेंट के साथ ग्रैडी प्राप्त करना होगा। इसके खिलाफ सिफारिश नहीं, सिर्फ यह कह रहा है कि आपको क्या करना है।

यकीन नहीं है कि आप सी में अनाम कार्यों को कैसे संभालेंगे। वॉन न्यूमैन मशीन पर, आप एएसएम में अनाम कार्य कर सकते हैं, हालांकि।



2

फेलिक्स भाषा C ++ को संकलित करता है। हो सकता है कि अगर आप C ++ को बुरा नहीं मानते हैं तो यह एक स्टेप स्टोन हो सकता है।


9
⁻¹ क्योंकि α) लेखक ने स्पष्ट रूप से उल्लेख किया है «नहीं C ++», C) एक संकलक द्वारा उत्पादित C ++ एक «मानव पठनीय C ++» नहीं होगा। γ) C ++ मानक एक कार्यात्मक प्रोग्रामिंग का समर्थन करता है, एक भाषा से दूसरी भाषा में संकलक का उपयोग करने की आवश्यकता नहीं है।
हाय-एंजेल

एक बार जब आप मैक्रोज़ या समान रूप से एक कार्यात्मक भाषा के साथ आते हैं, तो आप स्वचालित रूप से इसका मतलब है कि आप सी के लिए इतनी परवाह नहीं करते हैं। यह उत्तर मान्य और ठीक है क्योंकि यहां तक ​​कि सी ++ भी सी के शीर्ष पर मैक्रो पार्टी के रूप में शुरू हुआ था। काफी दूर तक उस सड़क से नीचे जाएं, आप एक नई भाषा के साथ समाप्त हो जाएंगे। तब यह केवल बैक एंड डिस्कशन के लिए नीचे आ रहा है।
BitTickler

1

अच्छी तरह से कुछ प्रोग्रामिंग भाषा सी में लिखी गई हैं और उनमें से कुछ प्रथम श्रेणी के नागरिकों के रूप में कार्य का समर्थन करते हैं, उस क्षेत्र की भाषाएं ecl (एम्बैडबल कॉमन लिस्प IIRC), गन्नो स्मॉलटॉक (gst) (स्मॉलटॉक में ब्लॉक हैं), फिर लाइब्रेरी हैं "बंद" के लिए जैसे glib2 http://library.gnome.org/devel/gobject/unstable/chapter-signal.html#closure जो कम से कम कार्यात्मक प्रोग्रामिंग के पास मिला। तो शायद कार्यात्मक प्रोग्रामिंग करने के लिए उन कार्यान्वयनों में से कुछ का उपयोग करना एक विकल्प हो सकता है।

अच्छी तरह से या आप Ocaml, Haskell, Mozart / Oz या इस तरह से सीख सकते हैं ;-)

सादर


क्या आप मुझे बताना चाहेंगे कि लाइब्रेरियों का उपयोग करने में ऐसा क्या गलत है जो प्रोग्रामिंग की FP शैली का कम से कम समर्थन करता है?
फ्रेडरिक

1

जिस तरह से मैं सी में कार्यात्मक प्रोग्रामिंग करने के बारे में गया था, सी में एक कार्यात्मक भाषा दुभाषिया लिखने के लिए था। मैंने इसे एफएक्सएल नाम दिया, जो "फ़ंक्शन एक्सप्रेशन लैंग्वेज" के लिए छोटा है।

दुभाषिया बहुत छोटा है, मेरे सिस्टम पर 68K के लिए संकलन -O3 सक्षम है। यह एक खिलौना भी नहीं है - मैं इसे अपने व्यवसाय के लिए लिखने वाले सभी नए उत्पादन कोड के लिए उपयोग कर रहा हूं (निवेश साझेदारी के लिए वेब-आधारित लेखांकन।)

अब मैं केवल (1) सी कोड लिखता हूं एक अंतर्निहित फ़ंक्शन को जोड़ता है जो एक सिस्टम रूटीन कहता है (जैसे कांटा, निष्पादन, सेट्रलिट, आदि), या (2) एक फ़ंक्शन को अनुकूलित करता है जो अन्यथा एफएक्सएल में लिखा जा सकता है (जैसे खोज एक विकल्प के लिए)।

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

http://fexl.com


-3

सी के बारे में यह क्या है कि आप कार्यात्मक, वाक्यविन्यास या शब्दार्थ बनाना चाहते हैं? कार्यात्मक प्रोग्रामिंग के शब्दार्थ निश्चित रूप से सी संकलक में जोड़े जा सकते हैं, लेकिन जब तक आप किए गए थे, तब तक आप अनिवार्य रूप से मौजूदा कार्यात्मक भाषाओं में से एक के बराबर होंगे, जैसे कि स्कीम, हास्केल, आदि।

यह उन भाषाओं के वाक्य विन्यास को सीखने के लिए समय का बेहतर उपयोग होगा जो सीधे उन शब्दार्थों का समर्थन करते हैं।


-3

सी। के बारे में न जानें, उद्देश्य-सी में कुछ कार्यात्मक विशेषताएं हैं हालांकि, ओएसएक्स पर जीसीसी भी कुछ सुविधाओं का समर्थन करता है, हालांकि मैं फिर से एक कार्यात्मक भाषा का उपयोग शुरू करने की सिफारिश करूंगा, ऊपर बहुत सारे उल्लेख किए गए हैं। मैंने व्यक्तिगत रूप से योजना के साथ शुरुआत की, द लिटिल स्कीमर जैसी कुछ उत्कृष्ट पुस्तकें हैं जो आपको ऐसा करने में मदद कर सकती हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.