user interface कार्यात्मक जीयूआई प्रोग्रामिंग संभव है?




user-interface haskell (12)

मैंने हाल ही में एफपी बग पकड़ा है (हास्केल सीखने की कोशिश कर रहा है), और मैं अब तक जो देखा है उससे पहले मैं वास्तव में प्रभावित हूं (प्रथम श्रेणी के कार्यों, आलसी मूल्यांकन, और अन्य सभी उपहार)। मैं अभी तक कोई विशेषज्ञ नहीं हूं, लेकिन मूलभूत एल्गोरिदम के लिए अनिवार्य रूप से "कार्यात्मक रूप से" कारणों को ढूंढना आसान हो गया है (और मुझे वापस जाने में परेशानी हो रही है)।

एक ऐसा क्षेत्र जहां वर्तमान एफपी फ्लैट गिरना प्रतीत होता है, हालांकि, जीयूआई प्रोग्रामिंग है। हास्केल दृष्टिकोण केवल अनिवार्य जीयूआई टूलकिट (जैसे जीटीके + या डब्ल्यूएक्सविड्ज) को लपेटना और एक अनिवार्य शैली को अनुकरण करने के लिए "डू" ब्लॉक का उपयोग करना प्रतीत होता है। मैंने एफ # का उपयोग नहीं किया है, लेकिन मेरी समझ यह है कि यह .NET कक्षाओं के साथ ओओपी का उपयोग करने जैसा कुछ करता है। जाहिर है, इसके लिए एक अच्छा कारण है - वर्तमान जीयूआई प्रोग्रामिंग आईओ और साइड इफेक्ट्स के बारे में है, इसलिए अधिकांश मौजूदा ढांचे के साथ पूरी तरह से कार्यात्मक प्रोग्रामिंग संभव नहीं है।

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


हास्केल दृष्टिकोण केवल अनिवार्य जीयूआई टूलकिट (जैसे कि जीटीके + या डब्ल्यूएक्सविड्जेट्स) को लपेटना और एक अनिवार्य शैली को अनुकरण करने के लिए "डू" ब्लॉक का उपयोग करना प्रतीत होता है

यह वास्तव में "हास्केल दृष्टिकोण" नहीं है - यह एक अनिवार्य इंटरफ़ेस के माध्यम से - आप केवल अनिवार्य जीयूआई टूलकिट से सीधे बाध्य करते हैं। हास्केल बस काफी प्रमुख बाइंडिंग होता है।

जीयूआई के लिए ज्यादातर मामूली परिपक्व, या अधिक प्रयोगात्मक पूरी तरह कार्यात्मक / घोषणात्मक दृष्टिकोण हैं, ज्यादातर हास्केल में, और मुख्य रूप से कार्यात्मक प्रतिक्रियाशील प्रोग्रामिंग का उपयोग करते हैं।

एक उदाहरण है

आप में से उन लोगों के लिए जिन्हें हास्केल, फ्लैपजैक्स से परिचित नहीं है, http://www.flapjax-lang.org/ जावास्क्रिप्ट के शीर्ष पर कार्यात्मक प्रतिक्रियाशील प्रोग्रामिंग का कार्यान्वयन है।


मेरा सवाल है, क्या जीयूआई प्रोग्रामिंग के लिए एक कार्यात्मक दृष्टिकोण होना संभव है?

आपके द्वारा खोजे जाने वाले प्रमुख शब्द "कार्यात्मक प्रतिक्रियाशील प्रोग्रामिंग" (एफआरपी) हैं।

कोनल इलियट और कुछ अन्य ने एफआरपी के लिए सही अमूर्तता खोजने की कोशिश करने से बाहर एक कुटीर उद्योग बनाया है। हास्केल में एफआरपी अवधारणाओं के कई कार्यान्वयन हैं।

आप कोनाल के सबसे हालिया "पुश-पुल फंक्शनल रिएक्टिव प्रोग्रामिंग" पेपर से शुरू करने पर विचार कर सकते हैं, लेकिन कई अन्य (पुराने) कार्यान्वयन हैं, कुछ हैकेल . org साइट से जुड़े हैं। कोनल के पास पूरे डोमेन को कवर करने के लिए एक नाटक है, और उसके पेपर को पहले जो हुआ था उसके संदर्भ में पढ़ा जा सकता है।

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


इन सभी अन्य उत्तरों को कार्यात्मक प्रोग्रामिंग पर बनाया गया है, लेकिन अपने स्वयं के डिज़ाइन निर्णय लेते हैं। एक पुस्तकालय जो मूल रूप से पूरी तरह से कार्यों और साधारण अमूर्त डेटा प्रकारों से बना है, gloss । यहां स्रोत से अपने play फ़ंक्शन के लिए प्रकार है

-- | Play a game in a window. Like `simulate`, but you manage your own input events.
play    :: Display              -- ^ Display mode.
        -> Color                -- ^ Background color.
        -> Int                  -- ^ Number of simulation steps to take for each second of real time.
        -> world                -- ^ The initial world.
        -> (world -> Picture)   -- ^ A function to convert the world a picture.
        -> (Event -> world -> world)    
                -- ^ A function to handle input events.
        -> (Float -> world -> world)
                -- ^ A function to step the world one iteration.
                --   It is passed the period of time (in seconds) needing to be advanced.
        -> IO ()

जैसा कि आप देख सकते हैं, यह सरल सार तत्वों के साथ शुद्ध कार्यों की आपूर्ति करके पूरी तरह से काम करता है, अन्य पुस्तकालय आपको सहायता करते हैं।


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

मैं इसे http://elm-lang.org पर जांचने का सुझाव देता हूं, जिसमें कुछ सचमुच उत्कृष्ट इंटरैक्टिव ट्यूटोरियल भी हैं जो पूरी तरह कार्यात्मक ब्राउज़र ब्राउज़र जीयूआई बनाने के तरीके पर हैं।

यह आपको पूरी तरह से कार्यात्मक जीयूआई बनाने की अनुमति देता है जहां आपको स्वयं को आपूर्ति करने के लिए आवश्यक कोड केवल शुद्ध कार्यों में शामिल होता है। मैंने व्यक्तिगत रूप से विभिन्न हास्केल जीयूआई ढांचे की तुलना में इसे प्राप्त करना बहुत आसान पाया।


एक्सयूएल जैसी मार्कअप भाषाएं आपको घोषणात्मक तरीके से जीयूआई बनाने की अनुमति देती हैं।


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


फंक्शनल रिएक्टिव प्रोग्रामिंग के पीछे दिमाग खोलने वाले विचारों में से एक घटना घटनाओं और अगली घटना हैंडलिंग फ़ंक्शन पर दोनों प्रतिक्रियाओं का उत्पादन करने वाला एक ईवेंट हैंडलिंग फ़ंक्शन है। इस प्रकार एक विकसित प्रणाली घटना प्रबंधन कार्यों के अनुक्रम के रूप में दर्शाया गया है।

मेरे लिए, यम्पा सीखना उस कार्य-उत्पादन-कार्य को ठीक से प्राप्त करने के लिए एक महत्वपूर्ण शिकार बन गया। यम्पा के बारे में कुछ अच्छे कागजात हैं। मैं यम्पा आर्केड की सिफारिश करता हूं:

http://www.cs.nott.ac.uk/~nhn/Talks/HW2003-YampaArcade.pdf (स्लाइड, पीडीएफ) http://www.cs.nott.ac.uk/~nhn/Publications/hw2003.pdf (पूरा लेख, पीडीएफ)

Haskell.org पर Yampa पर एक विकी पेज है

http://www.haskell.org/haskellwiki/Yampa

मूल यम्पा होम पेज:

http://www.haskell.org/yampa (दुर्भाग्य से इस समय टूटा हुआ है)


आप एफ # पर डॉन सिमे द्वारा श्रृंखला की जांच कर सकते हैं जहां वह डेमो बना रहा है। निम्न लिंक श्रृंखला के तीसरे भाग के लिए है (आप वहां से दूसरे दो भागों में लिंक कर सकते हैं)।

डब्ल्यूपीएफ विकास के लिए एफ # का उपयोग करना एक बहुत ही दिलचस्प जीयूआई प्रतिमान होगा ...

http://channel9.msdn.com/shows/Going+Deep/C9-Lectures-Dr-Don-Syme-Introduction-to-F-3-of-3/


चाहे आप एक संकर कार्यात्मक / ओओ भाषा जैसे एफ # या ओकैमल में हों, या पूरी तरह कार्यात्मक भाषा में जैसे हास्केल जहां साइड इफेक्ट्स आईओ मोनैड में रवाना हो जाएं, यह ज्यादातर मामला है कि जीयूआई को प्रबंधित करने के लिए आवश्यक काम का एक टन पूरी तरह से कार्यात्मक एल्गोरिदम की तरह "साइड इफेक्ट" की तरह अधिक है।

उस ने कहा, कार्यात्मक जीयूआई में कुछ वास्तव में ठोस शोध किया गया है। Fudgets या FranTk जैसे कुछ (अधिकतर) कार्यात्मक टूलकिट भी हैं।


मैं वास्तव में कहूंगा कि कार्यात्मक प्रोग्रामिंग (एफ #) यूजर इंटरफेस प्रोग्रामिंग के लिए उदाहरण सी # के मुकाबले ज्यादा बेहतर टूल है। आपको बस समस्या के बारे में थोड़ा अलग सोचने की जरूरत है।

मैं इस विषय पर अध्याय 16 में अपनी कार्यात्मक प्रोग्रामिंग पुस्तक में चर्चा करता हूं , लेकिन एक मुफ्त अंश उपलब्ध है , जो दिखाता है (आईएमएचओ) सबसे दिलचस्प पैटर्न जिसे आप एफ # में उपयोग कर सकते हैं। मान लें कि आप आयतों के चित्र को कार्यान्वित करना चाहते हैं (उपयोगकर्ता बटन को धक्का देता है, माउस को ले जाता है और बटन जारी करता है)। एफ # में, आप इस तरह कुछ लिख सकते हैं:

let rec drawingLoop(clr, from) = async { 
   // Wait for the first MouseMove occurrence 
   let! move = Async.AwaitObservable(form.MouseMove) 
   if (move.Button &&& MouseButtons.Left) = MouseButtons.Left then 
      // Refresh the window & continue looping 
      drawRectangle(clr, from, (move.X, move.Y)) 
      return! drawingLoop(clr, from) 
   else
      // Return the end position of rectangle 
      return (move.X, move.Y) } 

let waitingLoop() = async { 
   while true do
      // Wait until the user starts drawing next rectangle
      let! down = Async.AwaitObservable(form.MouseDown) 
      let downPos = (down.X, down.Y) 
      if (down.Button &&& MouseButtons.Left) = MouseButtons.Left then 
         // Wait for the end point of the rectangle
         let! upPos = drawingLoop(Color.IndianRed, downPos) 
         do printfn "Drawn rectangle (%A, %A)" downPos upPos }

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

कार्यात्मक प्रतिक्रियाशील प्रोग्रामिंग एक अधिक कार्यात्मक दृष्टिकोण है, लेकिन मुझे इसका उपयोग करना मुश्किल लगता है क्योंकि यह काफी उन्नत हास्केल सुविधाओं (जैसे तीर) पर निर्भर करता है। हालांकि, यह बड़ी संख्या में मामलों में बहुत ही सुरुचिपूर्ण है। यह सीमा यह है कि आप आसानी से एक राज्य मशीन को एन्कोड नहीं कर सकते (जो प्रतिक्रियाशील कार्यक्रमों के लिए एक उपयोगी मानसिक मॉडल है)। उपरोक्त एफ # तकनीक का उपयोग करके यह बहुत आसान है।


विंडोज प्रेजेंटेशन फाउंडेशन एक सबूत है कि कार्यात्मक दृष्टिकोण जीयूआई प्रोग्रामिंग के लिए बहुत अच्छी तरह से काम करता है। इसमें कई कार्यात्मक पहलू हैं और "अच्छा" डब्ल्यूपीएफ कोड (एमवीवीएम पैटर्न के लिए खोज) अनिवार्य पर कार्यात्मक दृष्टिकोण पर जोर देता है। मैं बहादुरी से दावा कर सकता हूं कि डब्ल्यूपीएफ सबसे सफल असली दुनिया की कार्यात्मक जीयूआई टूलकिट है :-)

डब्ल्यूपीएफ एक्सएएमएल में यूजर इंटरफेस का वर्णन करता है (हालांकि आप इसे सक्रिय रूप से सी # या एफ # को देखने के लिए फिर से लिख सकते हैं), इसलिए कुछ यूजर इंटरफेस बनाने के लिए आप लिखेंगे:

<!-- Declarative user interface in WPF and XAML --> 
<Canvas Background="Black">
   <Ellipse x:Name="greenEllipse" Width="75" Height="75" 
      Canvas.Left="0" Canvas.Top="0" Fill="LightGreen" />
</Canvas>

इसके अलावा, डब्ल्यूपीएफ आपको घोषणात्मक टैग के दूसरे सेट का उपयोग करके घटनाओं के लिए एनिमेशन और प्रतिक्रियाओं का घोषणा करने की अनुमति देता है (फिर भी, वही चीज़ सी # / एफ # कोड के रूप में लिखी जा सकती है):

<DoubleAnimation
   Storyboard.TargetName="greenEllipse" 
   Storyboard.TargetProperty="(Canvas.Left)"
   From="0.0" To="100.0" Duration="0:0:5" />

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


हास्केल के लिए नए लोगों द्वारा देखी गई सबसे स्पष्ट नवाचार यह है कि बाहरी दुनिया के साथ संवाद करने और गणना और एल्गोरिदम की शुद्ध दुनिया से संबंधित अशुद्ध दुनिया के बीच एक अलगाव है। एक लगातार शुरुआती सवाल यह है कि "मैं IO से कैसे छुटकारा पा सकता हूं, यानी, IO a में परिवर्तित कर सकता हूं?" इसका तरीका है IO और चेन प्रभावों को निष्पादित करने वाले कोड को लिखने के लिए monads (या अन्य abstractions) का उपयोग करना। यह कोड बाहरी दुनिया से डेटा एकत्र करता है, इसका एक मॉडल बनाता है, संभवतः शुद्ध कोड को नियोजित करके कुछ गणना करता है, और परिणाम आउटपुट करता है।

जहां तक ​​उपर्युक्त मॉडल का संबंध है, मुझे IO मोनैड में जीयूआई में हेरफेर करने के साथ बहुत कुछ गलत नहीं दिख रहा है। इस शैली से उत्पन्न होने वाली सबसे बड़ी समस्या यह है कि मॉड्यूल अब संगत नहीं हैं, यानी, मैं अपने कार्यक्रम में बयानों के वैश्विक निष्पादन आदेश के बारे में अपना अधिकांश ज्ञान खो देता हूं। इसे पुनर्प्राप्त करने के लिए, मुझे समवर्ती, अनिवार्य जीयूआई कोड के समान तर्क लागू करना होगा। इस बीच, अशुद्ध, गैर-जीयूआई कोड के लिए निष्पादन आदेश IO monad's >== ऑपरेटर की परिभाषा के कारण स्पष्ट है (कम से कम जब तक केवल एक धागा है)। शुद्ध कोड के लिए, इससे कोई फर्क नहीं पड़ता, प्रदर्शन को बढ़ाने के लिए कोने के मामलों को छोड़कर या मूल्यांकन के से बचने के लिए

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

एक कार्यात्मक तरीके से एसिंक्रोनस आईओ करने का एक लोकप्रिय दर्शन फंक्शनल रिएक्टिव प्रोग्रामिंग (एफआरपी) कहा जाता है। हाल ही में अशुद्ध, गैर-कार्यात्मक भाषाओं में ReactiveX जैसे पुस्तकालयों और एल्म जैसे ढांचे के लिए बहुत सारे कर्षण मिले। संक्षेप में, यह घटना स्रोतों के रूप में जीयूआई तत्वों और अन्य चीजों (जैसे फाइलें, घड़ियां, अलार्म, कीबोर्ड, माउस) को देखने जैसा है, जिसे "अवलोकन" कहा जाता है, जो घटनाओं की धाराओं को उत्सर्जित करते हैं। इन घटनाओं को नए धाराओं का उत्पादन करने के लिए परिचित ऑपरेटरों जैसे map , foldl , zip , filter , foldl , foldl का उपयोग करके संयुक्त किया जाता है। यह उपयोगी है क्योंकि कार्यक्रम राज्य स्वयं scanl . map reactToEvents $ zipN <eventStreams> रूप में देखा जा सकता है scanl . map reactToEvents $ zipN <eventStreams> scanl . map reactToEvents $ zipN <eventStreams> प्रोग्राम, जहां N प्रोग्राम द्वारा कभी भी देखा जाने वाले अवलोकनों की संख्या के बराबर है।

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







functional-programming