इंटरफ़ेस के लिए कार्यात्मक-प्रोग्रामिंग विकल्प क्या है?


15

यदि मैं एक "कार्यात्मक" शैली में कार्यक्रम करना चाहता हूं, तो मैं एक इंटरफ़ेस को क्या बदलूंगा?

interface IFace
{
   string Name { get; set; }
   int Id { get; }
}
class Foo : IFace { ... }

शायद ए Tuple<>?

Tuple<Func<string> /*get_Name*/, Action<String> /*set_Name*/, Func<int> /*get_Id*/> Foo;

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


संपादित करें: मैं क्या सोच रहा हूं / इसके बारे में कुछ और विस्तार।

कहो, मुझे एक विधि मिली है जिसमें तीन कार्य होते हैं:

static class Blarf
{
   public static void DoSomething(Func<string> getName, Action<string> setName, Func<int> getId);
}

का एक उदाहरण के साथ Barमैं इस विधि का उपयोग कर सकते हैं:

class Bar
{
   public string GetName();
   public void SetName(string value);

   public int GetId();
}
...
var bar = new Bar();
Blarf.DoSomething(bar.GetName, bar.SetName, bar.GetId);

लेकिन यह एक सा दर्द है क्योंकि मुझे barएक ही कॉल में तीन बार उल्लेख करना होगा । इसके अलावा, मैं वास्तव में फोन करने वालों के लिए विभिन्न उदाहरणों से कार्यों की आपूर्ति करने का इरादा नहीं रखता

Blarf.DoSomething(bar1.GetName, bar2.SetName, bar3.GetId); // NO!

C # में, इससे interfaceनिपटने का एक तरीका है; लेकिन यह एक बहुत ही वस्तु उन्मुख दृष्टिकोण की तरह लगता है। मैं सोच रहा था कि एक और अधिक कार्यात्मक समाधान है: 1) एक साथ फ़ंक्शन के समूह को पास करें, और 2) यह सुनिश्चित करें कि फ़ंक्शन ठीक से एक-दूसरे से संबंधित हैं।


आप नहीं करेंगे। डेटाटाइप्स के लिए इंटरफेस पूरी तरह से ठीक हैं (हालांकि आप अपरिवर्तनीय वस्तुओं का पक्ष लेंगे)।
तेलस्तीन

1
SICP का अध्याय 2 इस बारे में बहुत अधिक है।
user16764

7
अपने प्रश्न को फिर से तैयार करने के बाद, मैं उत्सुक हूं कि आप किस विशिष्ट कार्यक्षमता को पूरा करने की कोशिश कर रहे हैं? क्या आप के लिए पूछ रहा है कि कैसे एक कार्यात्मक शैली में एक उदाहरण के खिलाफ oo शैली पक्ष प्रभावी प्रोग्रामर है, जो समझ में नहीं आता है ..
जिमी Hoffa

इसका उत्तर भाषा-निर्भर होगा। क्लॉज्योर में आप clojure.org/protocols का उपयोग कर सकते हैं , जहां एकमात्र नरम क्षेत्र उन मापदंडों का प्रकार है, जिन पर फ़ंक्शंस को काम करना चाहिए - वे एक वस्तु हैं - जो आप सभी जानते हैं।
जॉब

1
इसे सरल बनाएं: एक ऐसी संरचना जिसमें पॉइंटर्स पॉइंट होते हैं, और एक ऑब्जेक्ट उदाहरण से इसे आरंभ करने के लिए एक फ़ंक्शन। हास्केल क्यों? ;)
mlvjjr

जवाबों:


6

कार्यात्मक प्रोग्रामिंग पर एक पतली लिबास के रूप में कार्यात्मक प्रोग्रामिंग का इलाज न करें; वहाँ सिर्फ एक सिंटैक्टिक अंतर से बहुत अधिक है।

इस मामले में, आपके पास एक GetIDतरीका है, जो वस्तुओं की विशिष्टता को दर्शाता है। कार्यात्मक कार्यक्रम लिखने के लिए यह एक अच्छा तरीका नहीं है। शायद आप हमें उस समस्या को बता सकते हैं जिसे आप हल करने की कोशिश कर रहे हैं और हम आपको अधिक सार्थक सलाह दे सकते हैं।


3
"आपको रूसी में सोचना चाहिए ।"
13

काफी उचित; मेरी असली समस्या विशेष रूप से दिलचस्प नहीं है। मुझे पहले से ही C # में ठीक काम करने वाली चीजें मिल गई हैं ( github.com/JDanielSmith/Projects/tree/master/PictureOfTheDay यदि आप वास्तव में कोड को देखना चाहते हैं), लेकिन यह अधिक कार्यात्मक शैली में करने के लिए मजेदार होगा अभी भी C # का उपयोग कर रहा है।
Ðаn

1
@ )Аn क्या यह वास्तव में फ़ायरफ़ॉक्स (फ़िल्म) उद्धरण है (क्योंकि अगर यह कमाल है)? या कहीं और इसका इस्तेमाल होता है?
icc97

2
जहाँ मैं मानता हूँ कि यह इंपीरियल से फंक्शनल प्रोग्रामिंग के लिए एक पूर्ण प्रतिमान है, वहाँ एक परिमाण में लिखे गए कोड की अधिक लाइनों के परिमाण के कई आदेश हैं। अत: विशाल प्रणालियों के लिए लिखे गए कोने के मामलों में बहुत कुछ अपूर्ण प्रोग्रामिंग के साथ पाया गया होगा। अपरिमित प्रोग्रामिंग में बहुत सारी अच्छी प्रथाएँ हैं और यह जानना कि क्या उन कौशलों का अनुवाद किया जा सकता है या यदि वे एफपी में एक गैर-मुद्दा हैं तो एक योग्य प्रश्न है। एफपी में भयानक कोड लिखना पूरी तरह से संभव है, इसलिए इस तरह के सवालों से एफपी के अच्छे हिस्सों को भी उजागर करना चाहिए।
icc97

11

हास्केल और इसके डेरिवेटिव में टाइपकास्ट हैं जो इंटरफेस के समान हैं। हालांकि ऐसा लगता है कि आप कैसे एनकैप्सुलेशन करने के बारे में पूछ रहे हैं, जो कि टाइप सिस्टम के बारे में एक सवाल है। हिंडले मिलनर प्रकार प्रणाली कार्यात्मक भाषाओं में आम है, और इसमें डेटा प्रकार हैं जो आपके लिए अलग-अलग भाषाओं में फैशन के लिए ऐसा करते हैं।


5
टाइपसेकल्स के लिए +1 - एक हास्केल टाइपकालेज़ और एक जावा इंटरफ़ेस के बीच मुख्य अंतर यह है कि दोनों प्रकार अलग-अलग घोषित किए जाने के बाद टाइपसेकल्स टाइप के साथ जुड़ा हुआ है । आप एक पुराने प्रकार का उपयोग एक नए "इंटरफ़ेस" के माध्यम से कर सकते हैं जितनी आसानी से आप एक नए प्रकार तक पहुँचने के लिए एक पुराने "इंटरफ़ेस" का उपयोग कर सकते हैं। डेटा छिपाने के लिए, आप मॉड्यूल में टाइप के कार्यान्वयन को छिपाते हैं। कम से कम के अनुसार एफिल प्रसिद्धि के बर्ट्रेंड मेयेर , एक OOP वर्ग है मॉड्यूल का एक प्रकार।
स्टीव ३१

5

एक फ़ंक्शन को कई इनपुट से निपटने की अनुमति देने के कुछ तरीके हैं।

पहला और सबसे आम: पैरामीट्रिक पॉलीमॉर्फिज़्म।

इससे मनमाने प्रकारों पर कार्य किया जा सकता है:

--Haskell Example
id :: a -> a --Here 'a' is just some arbitrary type
id myRandomThing = myRandomThing

head :: [a] -> a
head (listItem:list) = listItem

जो अच्छा है, लेकिन आपको गतिशील प्रेषण नहीं देता है जो OO इंटरफेस है। इसके लिए हास्केल के पास टाइपसेकल्स हैं, स्काला में इम्पीचिट्स आदि हैं

class Addable a where
   (<+>) :: a -> a -> a
instance Addable Int where
   a <+> b = a + b
instance Addable [a] where
   a <+> b = a ++ b

--Now we can get that do something similar to OO (kinda...)
addStuff :: (Addable a) => [a] -> a
-- Notice how we limit 'a' here to be something Addable
addStuff (x:[]) = x
addStuff (x:xs) = x <+> addStuff xs
-- In better Haskell form
addStuff' = foldl1 <+>

इन दो तंत्रों के बीच, आप अपने प्रकारों पर सभी प्रकार के जटिल और दिलचस्प व्यवहारों को व्यक्त कर सकते हैं।


1
जब जवाब में भाषा प्रश्न में भाषा से मेल नहीं खाती है तो आप सिंटैक्स हाइलाइटिंग संकेत जोड़ सकते हैं । उदाहरण के लिए मेरे सुझाए गए संपादन देखें।
हगोमग

1

मूल नियम-से-अंगूठा यह है कि FP प्रोग्रामिंग कार्यों में वही काम करते हैं जैसे ऑब्जेक्ट OO- प्रोग्रामिंग में करते हैं। आप उनके तरीकों (वैसे, "कॉल" विधि को वैसे भी) कह सकते हैं और वे कुछ एनकैप्सुलेटेड, आंतरिक नियमों के लिए रिकॉर्डिंग का जवाब देते हैं। विशेष रूप से, हर सभ्य एफपी भाषा आपको अपने फ़ंक्शन में क्लोजर / लेक्सिकल स्कूपिंग के साथ "उदाहरण चर" देती है।

var make_OO_style_counter = function(){
   return {
      counter: 0
      increment: function(){
          this.counter += 1
          return this.counter;
      }
   }
};

var make_FP_style_counter = function(){
    var counter = 0;
    return fucntion(){
        counter += 1
        return counter;
    }
};

अब अगला सवाल यह है कि एक इंटरफेस से आपका क्या मतलब है? एक दृष्टिकोण नाममात्र इंटरफेस का उपयोग कर रहा है (यह इंटरफ़ेस के अनुरूप है अगर यह कहता है कि ऐसा करता है) - यह एक आम तौर पर इस बात पर बहुत निर्भर करता है कि आप किस भाषा का उपयोग कर रहे हैं ताकि यह बाद के लिए छोड़ दें। इंटरफ़ेस को परिभाषित करने का दूसरा तरीका संरचनात्मक तरीका है, यह देखते हुए कि पैरामीटर क्या चीज़ प्राप्त करते हैं और वापस लौटते हैं। यह एक प्रकार का इंटरफ़ेस है जिसे आप गतिशील, डक-टाइप की गई भाषाओं में देखते हैं और यह FP के सभी के साथ बहुत अच्छी तरह से फिट बैठता है: एक इंटरफ़ेस हमारे कार्यों के लिए इनपुट मापदंडों का सिर्फ एक प्रकार है और वे जिस प्रकार से लौटते हैं, इसलिए सभी फ़ंक्शन मिलान करते हैं सही प्रकार इंटरफ़ेस फिट!

इसलिए, एक इंटरफ़ेस से मेल खाने वाली वस्तु का प्रतिनिधित्व करने का सबसे सीधा तरीका केवल कार्यों का एक समूह है। आप आमतौर पर कार्यों को किसी प्रकार के रिकॉर्ड में पैक करके अलग-अलग पारित करने की कुरूपता के आसपास आते हैं:

var my_blarfable = {
 get_name: function(){ ... },
 set_name: function(){ ... },
 get_id:   function(){ ... }
}

do_something(my_blarfable)

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

-- Explicit dictionary version
-- no setters because haskell doesn't like mutable state.
data BlargDict = BlargDict {
    blarg_name :: String,
    blarg_id   :: Integer
}

do_something :: BlargDict -> IO()
do_something blarg_dict = do
   print (blarg_name blarg_dict)
   print (blarg_id   blarg_dict)

-- Typeclass version   
class Blargable a where
   blag_name :: a -> String
   blag_id   :: a -> String

do_something :: Blargable a => a -> IO
do_something blarg = do
   print (blarg_name blarg)
   print (blarg_id   blarg)

हालांकि टाइपकास्ट के बारे में एक महत्वपूर्ण बात यह है कि शब्दकोशों प्रकारों से जुड़े होते हैं, न कि मूल्यों के साथ (जैसे कि शब्दकोश और OO संस्करण में क्या होता है)। इसका मतलब यह है कि टाइप सिस्टम आपको "टाइप" [1] मिश्रण करने की अनुमति नहीं देता है। यदि आप "blargables" की सूची चाहते हैं या blargables को लेने वाले एक बाइनरी फ़ंक्शन को टाइप करते हैं, तो टाइपकास्टल सब कुछ एक ही प्रकार के होने के लिए विवश कर देगा, जबकि शब्दकोश दृष्टिकोण आपको विभिन्न मूल के blargables देगा (जो संस्करण बेहतर है कि आप जो हैं उसमें बहुत कुछ निर्भर करता है) करते हुए)

[१] "अस्तित्वगत प्रकार" करने के उन्नत तरीके हैं लेकिन आमतौर पर यह परेशानी के लायक नहीं है।


0

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

;; returns a function of the type #'(lambda (x y z &optional a b c)

(defun get-higher-level-method-impl (some-type-of-qualifier) 
    (cond ((eq 'foo) #'the-foo-version)
          ((eq 'bar) #'the-bar-version)))
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.