2012-02-07 22 views
8

में मैं कुछ विधेय है, उदाहरण के लिए:Pointfree समारोह संयोजन अजगर

is_divisible_by_13 = lambda i: i % 13 == 0 
is_palindrome = lambda x: str(x) == str(x)[::-1] 

और तार्किक उन में के रूप में संयोजित करना चाहते हैं:

filter(lambda x: is_divisible_by_13(x) and is_palindrome(x), range(1000,10000)) 

सवाल अब है: इस तरह के संयोजन एक में लिखा जा सकता है pointfree शैली, जैसे:

filter(is_divisible_by_13 and is_palindrome, range(1000,10000)) 

यह नहीं वांछित प्रभाव क्योंकि निश्चित रूप से है लैम्ब्डा कार्यों की सच्चाई मूल्य True और and और or कम सर्किटिंग ऑपरेटरों रहे हैं। निकटतम बात मैं के साथ आया एक वर्ग P जो एक सरल विधेय कंटेनर कि __call__() लागू करता है और तरीकों and_() और or_() विधेय गठबंधन करने के लिए है परिभाषित करने के लिए किया गया था। P की परिभाषा इस प्रकार है:

P(is_divisible_by_13).and_(is_palindrome) 

जो ऊपर लैम्ब्डा समारोह के बराबर है:

import copy 

class P(object): 
    def __init__(self, predicate): 
     self.pred = predicate 

    def __call__(self, obj): 
     return self.pred(obj) 

    def __copy_pred(self): 
     return copy.copy(self.pred) 

    def and_(self, predicate): 
     pred = self.__copy_pred() 
     self.pred = lambda x: pred(x) and predicate(x) 
     return self 

    def or_(self, predicate): 
     pred = self.__copy_pred() 
     self.pred = lambda x: pred(x) or predicate(x) 
     return self 

P के साथ मैं अब एक नया विधेय है कि इस तरह विधेय का एक संयोजन है बना सकते हैं। यह मेरे पास जो कुछ भी है, उसके करीब आता है, लेकिन यह भी पॉइंटफ्री नहीं है (अंक अब उनके तर्कों के बजाय भविष्यवाणी कर रहे हैं)। अब दूसरा सवाल यह है: वहाँ (शायद कोष्ठकों और डॉट्स के बिना) P की तरह और (लैम्ब्डा) कार्यों का उपयोग किए बिना वर्गों का उपयोग करने से अजगर में विधेय गठबंधन करने के लिए एक बेहतर या कम रास्ता नहीं है?

+0

ऐसा लगता है कि आप एक कार्यात्मक भाषा की तरह व्यवहार करने वाली गैर-कार्यात्मक भाषा बनाने के लिए बहुत मेहनत कर रहे हैं। क्या आप पाइथन से बंधे हैं? –

+0

@Eric: हाँ, तरह का। मेरा पायथन कोड एक सी ++ प्रोजेक्ट में एम्बेडेड है और मैं सिर्फ दूसरी भाषा में स्विच नहीं कर सकता। –

उत्तर

8

कक्षा में __and__ विधि जोड़ कर आप पाइथन में & (बिटवाई और एंड ऑपरेटर) को ओवरराइड कर सकते हैं।

P(is_divisible_by_13) & P(is_palindrome) 

या यहाँ तक कि

P(is_divisible_by_13) & is_palindrome 
इसी

, आप जोड़ कर किसी __or__ विधि और ~ (बिटवाइज़ निषेध) ऑपरेटर जोड़कर | (बिटवाइज़ या) ऑपरेटर ओवरराइड कर सकते हैं: आप तो कुछ ऐसा लिख ​​सकता है एक __not__ विधि। ध्यान दें कि आप ओवरराइड नहीं कर सकते में निर्मित and, or और not ऑपरेटर, तो यह शायद संभव के रूप में अपने लक्ष्य के रूप में करीब है। तुम अब भी सबसे बाईं ओर के तर्क के रूप में एक P उदाहरण की आवश्यकता है।

पूर्णता के लिए के लिए, आप भी यथा-स्थान वेरिएंट (__iand__, __ior__) और इन ऑपरेटरों के दाईं ओर वेरिएंट (__rand__, __ror__) भी पार कर जाते।

कोड उदाहरण (अपरीक्षित, सही करने के लिए स्वतंत्र लग रहा है):

from functools import update_wrapper 

def predicate(func): 
    """Decorator that constructs a predicate (``P``) instance from 
    the given function.""" 
    result = P(func) 
    update_wrapper(result, func) 
    return result 

फिर आप टैग कर सकते हैं:

class P(object): 
    def __init__(self, predicate): 
     self.pred = predicate 

    def __call__(self, obj): 
     return self.pred(obj) 

    def __copy_pred(self): 
     return copy.copy(self.pred) 

    def __and__(self, predicate): 
     def func(obj): 
      return self.pred(obj) and predicate(obj) 
     return P(func) 

    def __or__(self, predicate): 
     def func(obj): 
      return self.pred(obj) or predicate(obj) 
     return P(func) 

एक और चाल आप बात से मुक्त करने के लिए निर्वाण निम्नलिखित डेकोरेटर है करीब लाने के लिए predicate सजावट के साथ आपकी भविष्यवाणी P स्वचालित रूप से एक उदाहरण बनाने के लिए:

@predicate 
def is_divisible_by_13(number): 
    return number % 13 == 0 

@predicate 
def is_palindrome(number): 
    return str(number) == str(number)[::-1] 

>>> pred = (is_divisible_by_13 & is_palindrome) 
>>> print [x for x in xrange(1, 1000) if pred(x)] 
[494, 585, 676, 767, 858, 949] 
+0

मुझे यकीन नहीं है कि मैं _bitwise_ ऑपरेटरों को किसी अन्य अर्थ से अधिभारित करना चाहता हूं, लेकिन मुझे सजावटी विचार बहुत दिलचस्प लगता है। धन्यवाद! –

+0

@ फ्रैंकएस। थॉमस: क्या बिटवाई ऑपरेशंस आपके भविष्यवाणियों के साथ कोई समझ में आता है? यदि नहीं, तो उन्हें अधिभारित करने में कुछ भी गलत नहीं है। –

3

मूल रूप से, आपका दृष्टिकोण पायथन में एकमात्र व्यवहार्य लगता है। बिंदु-मुक्त फ़ंक्शन संरचना को लागू करने के लिए मोटे तौर पर एक ही तंत्र का उपयोग करके python module on github है।

मैं इसे इस्तेमाल नहीं किया है, लेकिन एक पहली नजर में उसके समाधान (क्योंकि वह सज्जाकार और अधिक भार है जहाँ आप एक वर्ग और __call__ का उपयोग ऑपरेटर का उपयोग करता है) थोड़ा अच्छे लग रहा है।

लेकिन इसके अलावा यह तकनीकी रूप से पॉइंट-फ्री कोड नहीं है, यह सिर्फ "पॉइंट-छुपा" है यदि आप करेंगे। जो आपके लिए पर्याप्त हो सकता है या नहीं भी हो सकता है।

2

आप इस्तेमाल कर सकते हैं Infix operator recipe:

AND = Infix(lambda f, g: (lambda x: f(x) and g(x))) 
for n in filter(is_divisible_by_13 |AND| is_palindrome, range(1000,10000)): 
    print(n) 

पैदावार

1001 
2002 
3003 
4004 
5005 
6006 
7007 
8008 
9009 
+0

यह शायद 2012 के लिए पाइथन हैक ऑफ द ईयर है। कम से कम मेरे लिए। –

+0

@ तामास: नुस्खा पहले से ही 2005 का सबसे अच्छा हैक है :-) इसके अलावा, यह फर्डिनेंड जामित्स्की द्वारा है, मुझे नहीं। मैं केवल (abu?) इसे मेरे जवाब के लिए इस्तेमाल किया। – WolframH

1

यह मेरा समाधान होगा:

class Chainable(object): 

    def __init__(self, function): 
     self.function = function 

    def __call__(self, *args, **kwargs): 
     return self.function(*args, **kwargs) 

    def __and__(self, other): 
     return Chainable(lambda *args, **kwargs: 
           self.function(*args, **kwargs) 
           and other(*args, **kwargs)) 

    def __or__(self, other): 
     return Chainable(lambda *args, **kwargs: 
           self.function(*args, **kwargs) 
           or other(*args, **kwargs)) 

def is_divisible_by_13(x): 
    return x % 13 == 0 

def is_palindrome(x): 
    return str(x) == str(x)[::-1] 

filtered = filter(Chainable(is_divisible_by_13) & is_palindrome, 
        range(0, 100000)) 

i = 0 
for e in filtered: 
    print str(e).rjust(7), 
    if i % 10 == 9: 
     print 
    i += 1 

और ये मेरे परिणाम है:

0  494  585  676  767  858  949 1001 2002 3003 
4004 5005 6006 7007 8008 9009 10101 11011 15951 16861 
17771 18681 19591 20202 21112 22022 26962 27872 28782 29692 
30303 31213 32123 33033 37973 38883 39793 40404 41314 42224 
43134 44044 48984 49894 50505 51415 52325 53235 54145 55055 
59995 60606 61516 62426 63336 64246 65156 66066 70707 71617 
72527 73437 74347 75257 76167 77077 80808 81718 82628 83538 
84448 85358 86268 87178 88088 90909 91819 92729 93639 94549 
95459 96369 97279 98189 99099 
1

पायथन पहले से ही दो कार्यों के संयोजन का एक तरीका है: लैम्ब्डा। आप आसानी से अपनी रचना बना सकते हैं और कई रचनात्मक कार्य कर सकते हैं:

compose2 = lambda f,g: lambda x: f(g(x)) 
compose = lambda *ff: reduce(ff,compose2) 

filter(compose(is_divisible_by_13, is_palindrome, xrange(1000))) 
+0

यह 'कम (compose2, एफएफ) 'होना चाहिए, या बस' कम करें (लैम्ब्डा एफ, जी: लैम्ब्डा एक्स: एफ (जी (एक्स)), एफएफ)' – modular