क्या एक ही समय में करी और चर समारोह करना संभव है?


13

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

यहाँ कुछ छद्मकोड हैं:

sum = if @args.empty then 0 else @args.head + sum @args.tail

जो माना जाता है कि इसके सभी तर्कों का योग है। फिर, यदि sumखुद को एक नंबर माना जाता है, तो इसका परिणाम है 0। उदाहरण के लिए,

sum + 1

1 के बराबर है, यह मानते हुए कि +केवल संख्याओं पर काम कर सकते हैं। हालांकि, यह भी sum == 0सच है, sumफिर भी अपने मूल्य और कार्यात्मक संपत्ति को बनाए रखेगा चाहे कोई भी तर्क दिया जाए (इसलिए "आंशिक रूप से लागू किया गया" और "वैरेडिक" एक ही समय में), उदाहरण के लिए, अगर मैं घोषणा करता हूं

g = sum 1 2 3

तब gके बराबर है 6, हालांकि, हम अभी भी आगे आवेदन कर सकते हैं g। उदाहरण के लिए, g 4 5 == 15सत्य है। इस स्थिति में, हम ऑब्जेक्ट gको शाब्दिक रूप से प्रतिस्थापित नहीं कर सकते हैं 6, क्योंकि जब वे पूर्णांक के रूप में व्यवहार किए जाते हैं, तो समान मान प्राप्त करते हैं, उनके अंदर अन्य कोड होते हैं।

यदि इस डिज़ाइन का उपयोग वास्तविक प्रोग्रामिंग भाषा में किया जाता है, तो क्या यह किसी भ्रम या अस्पष्टता का कारण होगा?


1
कड़ाई से बोलना, किसी भाषा के मूल के रूप में करीने का उपयोग करने का अर्थ है कि सभी कार्य एक समान हैं - न केवल कोई चर कार्य नहीं हैं, बल्कि कोई द्विआधारी भी नहीं हैं! हालाँकि, उस भाषा के कार्यक्रम अभी भी दिखेंगे जैसे कि उन्होंने कई तर्क दिए हैं, और यह वैरिएबल कार्यों के लिए भी उतना ही सामान्य है जितना कि सामान्य लोगों के लिए।
किलन फथ

फिर मेरा प्रश्न सरल है "क्या कोई वस्तु एक फ़ंक्शन और एक ही समय में एक गैर-फ़ंक्शन मान हो सकती है?" उपरोक्त उदाहरण में, sumहै 0एक तर्क के बिना और रिकर्सिवली एक तर्क के साथ खुद को कहता है।
माइकल त्सांग

का काम नहीं है reduce?
शाफ़्ट सनकी

1
कार्यों आप पर प्रयोग कर रहे हैं पर एक नज़र डालें args: empty, head, और tail। वे सभी सूची कार्य हैं, जो यह सुझाव देते हैं कि शायद आसान और अधिक सीधी बात यह है कि एक सूची का उपयोग करना होगा जहां वैरेडिक सामान होगा। (इसलिए, sum [1, 2, 3]इसके बजाय sum 1 2 3)
माइकल शॉ

जवाबों:


6

वेरगेज को कैसे लागू किया जा सकता है? हमें तर्क सूची के अंत का संकेत देने के लिए कुछ तंत्र की आवश्यकता है। यह या तो हो सकता है

  • एक विशेष टर्मिनेटर मान, या
  • अतिरिक्त पैरामीटर के रूप में पास की गई वैरग सूची की लंबाई।

इन दोनों तंत्रों का उपयोग वैराग्य को लागू करने के लिए करी के संदर्भ में किया जा सकता है, लेकिन उचित टाइपिंग एक प्रमुख मुद्दा बन जाता है। मान लेते हैं कि हम एक फ़ंक्शन के साथ काम कर रहे हैं sum: ...int -> int, सिवाय इसके कि यह फ़ंक्शन करी का उपयोग करता है (इसलिए हमारे पास वास्तव में एक प्रकार अधिक पसंद है sum: int -> ... -> int -> int, सिवाय इसके कि हम तर्कों की संख्या नहीं जानते हैं)।

मामला: टर्मिनेटर मान: endविशेष टर्मिनेटर होने दें, और Tइसका प्रकार हो sum। अब हम जानते हैं कि endफ़ंक्शन रिटर्न पर लागू होता है : sum: end -> intऔर यह कि इंट में लागू होने पर हमें एक और योग जैसा फ़ंक्शन मिलता है sum: int -> T:। इसलिए Tइन प्रकार का मिलन है: T = (end -> int) | (int -> T)। प्रतिस्थापन करके T, हम इस तरह के रूप में विभिन्न प्रकार के संभव पाने के end -> int, int -> end -> int, int -> int -> end -> int, आदि हालांकि, ज्यादातर प्रकार सिस्टम इस तरह के प्रकारों को समायोजित नहीं है।

मामला: स्पष्ट लंबाई: एक vararg फ़ंक्शन का पहला तर्क varargs की संख्या है। तो sum 0 : int, sum 1 : int -> int, sum 3 : int -> int -> int -> intआदि यह कुछ प्रकार प्रणालियों में समर्थन किया और का एक उदाहरण है है निर्भर टाइपिंग । - वास्तव में, तर्क की संख्या एक प्रकार पैरामीटर और नहीं एक नियमित पैरामीटर होगा यह समारोह की arity एक क्रम मूल्य पर निर्भर करने के लिए कोई मतलब नहीं होगा, s = ((sum (floor (rand 3))) 1) 2या तो यह मूल्यांकन करता है: स्पष्ट रूप से बीमार टाइप है s = ((sum 0) 1) 2 = (0 1) 2, s = ((sum 1) 1) 2 = 1 2या s = ((sum 2) 1) 2 = 3

व्यवहार में, इनमें से कोई भी तकनीक का उपयोग नहीं किया जाना चाहिए क्योंकि वे त्रुटि-प्रवण हैं, और सामान्य प्रकार के सिस्टम में एक (सार्थक) प्रकार नहीं है। इसके बजाय, बस एक मानदंड के रूप में मानों की एक सूची पास करें sum: [int] -> int:।

हां, किसी ऑब्जेक्ट के लिए फ़ंक्शन और मान दोनों के रूप में प्रकट होना संभव है, उदाहरण के लिए एक प्रकार की प्रणाली में। आज्ञा sumदेना एक SumObj, जो दो coercions है:

  • coerce: SumObj -> int -> SumObjsumएक समारोह के रूप में इस्तेमाल करने की अनुमति देता है, और
  • coerce: SumObj -> int हमें परिणाम निकालने की अनुमति देता है।

तकनीकी तौर पर, यह ऊपर टर्मिनेटर मूल्य मामले की एक विविधता है, साथ T = SumObj, और coerceप्रकार के लिए एक गैर-आवरण जा रहा है। कई ऑब्जेक्ट-ओरिएंटेड भाषाओं में, यह ऑपरेटर ओवरलोडिंग के साथ तुच्छ रूप से लागू करने योग्य है, जैसे C ++:

#include <iostream>
using namespace std;

class sum {
  int value;
public:
  explicit sum() : sum(0) {}
  explicit sum(int x) : value(x) {}
  sum operator()(int x) const { return sum(value + x); }  // function call overload
  operator int() const { return value; } // integer cast overload
};

int main() {
  int zero = sum();
  cout << "zero sum as int: " << zero << '\n';
  int someSum = sum(1)(2)(4);
  cout << "some sum as int: " << someSum << '\n';
}

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

आप अपने स्वयं के उच्च क्रम फ़ंक्शन को बना सकते हैं जो आंशिक रूप से एक फ़ंक्शन को लागू करता है जो एक सूची लेता है, जैसे curryList : ([a] -> b) -> [a] -> [a] -> b, curryList f xs ys = f (xs ++ ys)
जैक

2

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

मेरी राय में, ये दृष्टिकोण थोड़ा हैक हैं, लेकिन वे बताते हैं कि यह संभव है। यदि आपकी भाषा में पूर्ण आश्रित टाइपिंग की सुविधा है, तथापि, यह बहुत सरल है। इसके पूर्णांक तर्कों को योग करने के लिए एक चर समारोह तब कुछ इस तरह दिख सकता है:

type SumType = (t : union{Int,Null}) -> {SumType, if t is Int|
                                         Int,     if t is Null}
sum :: SumType
sum (v : Int) = v + sum
sum (v : Null) = 0

एक स्पष्ट नाम देने की आवश्यकता के बिना पुनरावर्ती प्रकार को परिभाषित करने के लिए एक अमूर्तता इस तरह के कार्यों को लिखना आसान बना सकती है।

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


0

यहाँ Python3 में वैरिएड फ़ंक्शंस की करीकरण के लिए एक संस्करण है जो पायथन के वैकल्पिक तर्कों का लाभ उठाकर @amon के "टर्मिनेटर" दृष्टिकोण का उपयोग करता है:

def curry_vargs(g):
    actual_args = []
    def f(a, force=False):
        nonlocal actual_args
        actual_args.append(a)
        if force:
            res = g(*actual_args)
            actual_args = []
            return res
        else:
            return f
    return f

def g(*args): return sum(args)
f = curry_vargs(g)
f(1)(2)(3)(4,True) # => 10

लौटाया गया फ़ंक्शन इसके द्वारा पास किए गए fतर्कों को एक सरणी में क्रमिक कॉल में इकट्ठा करता है जो बाहरी दायरे में बंधा हुआ है। केवल जब forceतर्क सत्य होता है तो मूल फ़ंक्शन को अब तक एकत्रित सभी तर्कों के साथ कहा जाता है।

इस कार्यान्वयन के कारण यह है कि आपको हमेशा एक पहला तर्क पारित करना होता है fताकि आप "थंक" न बना सकें, एक ऐसा कार्य जहां सभी तर्क बाध्य हों और उन्हें केवल रिक्त तर्क सूची के साथ बुलाया जा सके (लेकिन मुझे लगता है कि यह इसके अनुरूप है के विशिष्ट कार्यान्वयन)।

एक और चेतावनी यह है कि एक बार जब आप एक गलत तर्क (जैसे गलत प्रकार) पास कर लेते हैं, तो आपको मूल कार्य को फिर से करना होगा। आंतरिक सरणी को रीसेट करने का कोई अन्य तरीका नहीं है, यह केवल करी फ़ंक्शन के सफल निष्पादन के बाद किया जाता है।

मुझे नहीं पता कि आपका सरलीकृत प्रश्न, "क्या एक वस्तु एक फ़ंक्शन और एक ही समय में एक गैर-फ़ंक्शन मान हो सकती है?", पायथन में कार्यान्वित किया जा सकता है, बिना किसी फ़ंक्शन के संदर्भ के बिना कोष्ठक आंतरिक फ़ंक्शन ऑब्जेक्ट का मूल्यांकन करता है। । मुझे नहीं पता कि क्या यह एक मनमाना मूल्य वापस करने के लिए तुला हो सकता है।

संभवतः लिस्प में यह आसान होगा, क्योंकि लिस्प प्रतीकों में एक ही समय में एक मूल्य और एक फ़ंक्शन मान हो सकता है; फ़ंक्शन मान बस तब चुना जाता है जब प्रतीक फ़ंक्शन स्थिति में प्रकट होता है (किसी सूची में पहला तत्व)।

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