अजगर करी और आंशिक

Aug 19 2020

कोडवर्ड डॉट कॉम पर प्रोग्रामिंग अभ्यास करते समय, मुझे करी और आंशिक कार्यों पर एक अभ्यास का सामना करना पड़ा ।

प्रोग्रामिंग में एक नौसिखिया और विषय के लिए नया होने के नाते, मैंने इस विषय पर जानकारी के लिए इंटरनेट पर खोज की और अभ्यास को हल करने में काफी दूर हो गया। हालांकि मैं अब एक बाधा पर ठोकर खाई है जिसे मैं दूर नहीं कर पा रहा हूं और यहां सही दिशा में एक कुहनी की तलाश में हूं।

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

व्यायाम लिंक के बाद, सभी परीक्षण मामलों में पाया जा सकता है कि फ़ंक्शन को संभालने में सक्षम होने की आवश्यकता है।

मैं जिस कोड के साथ आया वह निम्नलिखित है:

from functools import partial
from inspect import signature

def curry_partial(func, *initial_args):
    """ Generates a 'curried' version of a function. """

    # Process any initial arguments that where given. If the number of arguments that are given exceeds 
    # minArgs (the number of input arguments that func needs), func is evaluated

    minArgs = len(signature(func).parameters)
    if initial_args:
        if len(initial_args) >= minArgs: 
            return func(*initial_args[:minArgs])

        func = partial(func, *initial_args)
        minArgs = len(signature(func).parameters)

    
    # Do the currying
    def g(*myArgs):
        nonlocal minArgs

        # Evaluate function if we have the necessary amount of input arguments
        if minArgs is not None and minArgs <= len(myArgs):
                return func(*myArgs[:minArgs]) 
            
        def f(*args):
            nonlocal minArgs
            newArgs = myArgs + args if args else myArgs

            if minArgs is not None and minArgs <= len(newArgs):
                return func(*newArgs[:minArgs])
            else:
                return g(*newArgs)  
        return f
    return g

जब निम्न परीक्षण निष्पादित किया जाता है तो अब यह कोड विफल हो जाता है:

test.assert_equals(curry_partial(curry_partial(curry_partial(add, a), b), c), sum)

जहाँ पर = a + b + c (ठीक से परिभाषित फंक्शन), a = 1, b = 2, c = 3, और sum = 6 जोड़ें।

यह कारण विफल हो जाता है क्योंकि curry_partial(add, a)फ़ंक्शन को फ़ंक्शन हैंडल देता है g। दूसरी कॉल में curry_partial(<function_handle to g>, b), गणना minArgs = len(signature(func).parameters)काम नहीं करती है जैसे मैं इसे चाहता हूं, क्योंकि यह अब गणना करेगा कि कितने इनपुट तर्क फ़ंक्शन की gआवश्यकता है (जो कि 1: यानी *myArgs), और न कि कितने मूल funcअभी भी आवश्यक हैं। तो सवाल यह है कि, मैं अपने कोड को कैसे लिख सकता हूं, ताकि मैं इस बात पर नज़र रख सकूं कि मेरी मूल funcअभी भी ज़रूरतों के लिए कितने इनपुट तर्क हैं (हर बार जब मैं किसी भी प्रारंभिक दलील के साथ फ़ंक्शन को पूरा कर रहा हूं तो उस संख्या को कम कर देता हूं)।

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

जवाब

1 Ava Aug 20 2020 at 13:27

इसे आज़माएं।

from inspect import signature

# Here `is_set` acts like a flip-flop
is_set = False
params = 0

def curry_partial(func, *partial_args):
    """
    Required argument: func
    Optional argument: partial_args
    Return:
        1) Result of the `func` if
           `partial_args` contains
           required number of items.
        2) Function `wrapper` if `partial_args`
           contains less than the required
           number of items.
    """

    global is_set, params
    
    if not is_set:
        is_set = True
        
        # if func is already a value
        # we should return it
        try: params = len(signature(func).parameters)
        except: return func
    
    try:
        is_set = False
        return func(*partial_args[:params])
    
    except:
        is_set = True
    
        def wrapper(*extra_args):
            """
            Optional argument: extra_args
            Return:
                1) Result of the `func` if `args`
                   contains required number of
                   items.
                2) Result of `curry_partial` if
                   `args` contains less than the
                   required number of items.
            """
            
            args = (partial_args + extra_args)
            
            try:
                is_set = False
                return func(*args[:params])
            except:
                is_set = True
                return curry_partial(func, *args)
    
    return wrapper

यह वास्तव में डिजाइन द्वारा बहुत अच्छा नहीं है। इसके बजाय आपको उपयोग करना चाहिए class, जैसे कि सभी आंतरिक कार्य करने के लिए, उदाहरण के लिए, फ्लिप-फ्लॉप (चिंता न करें कि हमें वहां किसी भी फ़्लॉप-फ़्लॉप की आवश्यकता नहीं है;;)।

जब भी कोई फ़ंक्शन होता है जो मनमानी तर्क लेता है, तो आप हमेशा फ़ंक्शन को पास करने वाले उस वर्ग को तुरंत कर सकते हैं। लेकिन इस बार हालांकि, मैं उस पर तुम्हें छोड़ देता हूं।

Nishant Aug 21 2020 at 02:46

मैं करी के बारे में निश्चित नहीं हूं , लेकिन अगर आपको एक साधारण आंशिक फ़ंक्शन जनरेटर की आवश्यकता है, तो आप कुछ इस तरह की कोशिश कर सकते हैं:

from functools import partial
from inspect import signature

def execute_or_partial(f, *args):
    max = len(signature(f).parameters)
    if len(args) >= max: 
        return f(*args[:max])
    else:
        return partial(f, *args)

s = lambda x, y, z: x + y + z

t = execute_or_partial(s, 1)
u = execute_or_partial(t, 2)
v = execute_or_partial(u, 3)

print(v)

or

print(execute_or_partial(execute_or_partial(execute_or_partial(s, 1), 2), 3))

यहां तक ​​कि अगर यह आपकी मूल समस्या को हल नहीं करता है, तो देखें कि क्या आप कोड पुनरावृत्ति को कम करने के लिए उपरोक्त कोड का उपयोग कर सकते हैं (मुझे यकीन नहीं है, लेकिन मुझे लगता है कि आंतरिक फ़ंक्शन में कुछ कोड पुनरावृत्ति है?)। जो बाद की समस्याओं को हल करना आसान बना देगा।

मानक पुस्तकालय में कार्य हो सकते हैं जो पहले से ही इस समस्या को हल करते हैं। हास्केल जैसी कई शुद्ध कार्यात्मक भाषाओं में यह सुविधा भाषा में निर्मित है।