क्या इस समस्या का एक शुद्ध-कार्यात्मक समाधान अनिवार्य के रूप में साफ हो सकता है?


10

मैंने पायथन में एक अभ्यास किया है:

  • बहुपद को गुणांक के एक समूह के रूप में दिया जाता है, जैसे कि शक्तियां सूचकांक द्वारा निर्धारित की जाती हैं, जैसे: (9,7,5) का अर्थ है 9 + 7 * x + 5 * x ^ 2

  • दिए गए x के लिए इसके मान की गणना करने के लिए एक फ़ंक्शन लिखें

चूंकि मैं हाल ही में कार्यात्मक प्रोग्रामिंग में हूं, इसलिए मैंने लिखा

def evaluate1(poly, x):
  coeff = 0
  power = 1
  return reduce(lambda accu,pair : accu + pair[coeff] * x**pair[power],
                map(lambda x,y:(x,y), poly, range(len(poly))),
                0)

जो मैं अपठनीय हूं, इसलिए मैंने लिखा

def evaluate2(poly, x):
  power = 0
  result = 1
  return reduce(lambda accu,coeff : (accu[power]+1, accu[result] + coeff * x**accu[power]),
                poly,
                (0,0)
               )[result]

जो कम से कम अपठनीय है, इसलिए मैंने लिखा

def evaluate3(poly, x):
  return poly[0]+x*evaluate(poly[1:],x) if len(poly)>0 else 0

जो कम कुशल हो सकता है (संपादित करें: मैं गलत था!) ​​क्योंकि यह घातांक के बजाय कई गुणा का उपयोग करता है, सिद्धांत रूप में, मैं यहां माप के बारे में परवाह नहीं करता हूं (संपादित करें: मुझे कितना मूर्खतापूर्ण! माप ने मेरी गलतफहमी को इंगित किया होगा!) अभी भी पठनीय के रूप में पठनीय (यकीनन) नहीं है:

def evaluate4(poly, x):
  result = 0
  for i in range(0,len(poly)):
      result += poly[i] * x**i
  return result

क्या दक्षता के रूप में पठनीय के रूप में एक शुद्ध-कार्यात्मक समाधान है और दक्षता में इसके करीब है?

बेशक, एक प्रतिनिधित्व परिवर्तन में मदद मिलेगी, लेकिन यह अभ्यास द्वारा दिया गया था।

केवल पायथन ही नहीं, हास्केल या लिस्प भी हो सकते हैं।


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

2
BTW गुणन विधि हॉर्नर की विधि है और यह प्रत्येक चरण में घातांक की तुलना में अधिक कुशल है, क्योंकि घातांक को बहुत समान गुणन की आवश्यकता होती है और फिर कुछ और।

1
जब आप lambdaहल्के अनाम सिंटैक्स फ़ंक्शन वाली भाषाओं की तुलना में पायथन थोड़े बदसूरत रूप से बदसूरत हो जाते हैं । इसका एक हिस्सा संभवतः "अशुद्ध" उपस्थिति में योगदान देता है।
KChaloux

@KCououx कि वास्तव में मैं क्या कहने जा रहा था। कार्यात्मक प्रोग्रामिंग समर्थन कुछ मामलों में पायथन में बाद में हुआ है और यह इस तरह के शो है। यहां तक ​​कि मुझे नहीं लगता कि पहला संस्करण इतना भयानक रूप से अपठनीय है कि आप समझ नहीं सकते कि क्या चल रहा है।
एविक्टाटॉस

मैं वास्तव में आपके कोड से भ्रमित हूं, जबकि समस्या-गुंजाइश में एक गणितीय समीकरण है जो बेहद स्पष्ट है, आप सिर्फ उस गणित समीकरण का उपयोग क्यों नहीं करते हैं? यह किसी भी भाषा को दिए गए एक फ़ंक्शन में आसानी से बदल जाता है ... निश्चित नहीं है कि जब आप किसी एकल समीकरण का मूल्यांकन करने वाले फ़ंक्शन के लिए पूछ रहे हैं, तो वह मैप या कम या पुनरावृति करना चाहता है या नहीं और उस समीकरण को देता है - यह नहीं पूछता है सभी पर पुनरावृति ...
जिमी हॉफ

जवाबों:


13

हॉर्नर की विधि शायद अधिक कम्प्यूटेशनल रूप से कुशल है क्योंकि @delnan बताते हैं, लेकिन मैं इस सुंदर पठनीय को घातांक समाधान के लिए कहूंगा:

def eval_poly(poly, x):
    return sum( [a * x**i for i,a in enumerate(poly)] )

17
वर्ग कोष्ठक sum(coeff * X**power for power, coeff in enumerate(poly))
गिराएं

1
यह मुझे दुखद लगता है कि अन्य पोस्ट किए गए उत्तर इतने जटिल हैं। अपने लाभ के लिए भाषा का प्रयोग करें!
इजाकाता

समझ कार्यात्मक प्रोग्रामिंग में "तस्करी" के लिए लूप की तरह है
user1358

7
@ user1358 नहीं, यह की संरचना के लिए वाक्य रचना चीनी है mapऔर filter। कोई इसे किसी विशेष आकार के लूप के रूप में भी सोच सकता है, लेकिन उस आकार के लूप उपर्युक्त कवकनाशक कॉम्बीनेटर के बराबर होते हैं।

7

कई कार्यात्मक भाषाओं में मैपी कार्यान्वयन होता है जो आपको एक मानचित्र के माध्यम से एक सूचकांक बुनाई की अनुमति देता है। एक राशि के साथ संयोजन करें और आपके पास F # में निम्नलिखित हैं:

let compute coefficients x = 
    coefficients 
        |> Seq.mapi (fun i c -> c * Math.Pow(x, (float)i))
        |> Seq.sum

2
और यहां तक ​​कि अगर वे नहीं करते हैं, तब तक जब तक आप समझते हैं कि कैसे mapकाम करता है, तो अपने स्वयं के लेखन में बहुत सरल होना चाहिए।
KChaloux

4

मुझे समझ नहीं आ रहा है कि आपका कोड आपके द्वारा बताई गई समस्या के दायरे से कैसे संबंधित है, इसलिए मैं आपके संस्करण को समस्या के दायरे को अनदेखा करने के बारे में बताऊंगा।

सुंदर पठनीय हैस्केल (यह दृष्टिकोण किसी भी एफपी भाषा में आसानी से अनुवादित किया जा सकता है जिसमें विनाशकारी सूची है और शुद्ध और पठनीय है)

eval acc exp val [] = acc
eval acc exp val (x:xs) = eval (acc + execPoly) (exp+1) xs
  where execPoly = x * (val^exp)

कभी-कभी हैस्केल में भोली सरल दृष्टिकोण एफपी के आदी लोगों के लिए अधिक संक्षिप्त दृष्टिकोण की तुलना में क्लीनर है।

एक और स्पष्ट रूप से अनिवार्य दृष्टिकोण जो अभी भी पूरी तरह से शुद्ध है:

steval val poly = runST $ do
  accAndExp <- newSTRef (0,1)
  forM_ poly $ \x -> do
    modifySTRef accAndExp (updateAccAndExp x)
  readSTRef accAndExp
  where updateAccAndExp x (acc, exp) = (acc + x*(val^exp), exp + 1)

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

हालांकि कुछ निश्चित होने के लिए, एक हास्केलर से सबसे अधिक वास्तविक कार्यान्वयन ऊपर दिए गए दूसरे उत्तर में उल्लिखित ज़िपविथ होगा। zipWithएक बहुत ही विशिष्ट दृष्टिकोण है और मेरा मानना ​​है कि पायथन संयोजन कार्यों के ज़िपिंग दृष्टिकोण और एक अनुक्रमणिका की नकल कर सकता है जिसे मैप किया जा सकता है।


4

यदि आपके पास बस (निश्चित) टपल है, तो ऐसा क्यों नहीं करें (हास्केल में):

evalPolyTuple (c, b, a) x = c + b*x + a*x^2

यदि आपके पास गुणांक की एक सूची है, तो आप उपयोग कर सकते हैं:

evalPolyList coefs x = sum $ zipWith (\c p -> c*x^p) coefs [0..]

या आपके पास एक कमी के साथ:

evalPolyList' coefs x = foldl' (\sum (c, p) -> sum + c*x^p) 0 $ zip coefs [0..]

1
यह होमवर्क नहीं है! यह उल्लेख करने के लिए नहीं कि मैंने पहले से ही 3 समाधान किए थे।
user1358

पाइथन में आधा समय (इस मामले में शामिल है), "टपल" का अर्थ "अपरिवर्तनीय सूची" है और इसलिए यह मनमाना लंबाई है।

स्पष्ट रूप से मनमानी लंबाई
user1358

1
अजगर की वजह से नहीं, बल्कि इसलिए कि बहुपद मनमानी लंबाई का अर्थ है, और निश्चित आकार एक व्यायाम का एक बड़ा नहीं होगा
user1358

1
@delnan यह दिलचस्प है। मैंने हमेशा tupleमानों के एक निश्चित आकार के सेट का अर्थ लिया है, प्रत्येक संभावित भिन्न प्रकार के, जिन्हें जोड़ा या हटाया नहीं जा सकता है। मैं वास्तव में कभी नहीं समझ पाया कि सूचियों के साथ एक गतिशील भाषा, जो विषम इनपुट को स्वीकार करती है, उनकी आवश्यकता होगी।
KChaloux

3

कार्यात्मक एल्गोरिदम की पठनीयता में सुधार करने के लिए आपके द्वारा उपयोग किए जाने वाले चरणों का एक सामान्य सेट है:

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