फ़ंक्शंस के लिए एक टाइपकास्ट क्यों नहीं है?


17

एक सीखने की समस्या में, जिसके साथ मैं खिलवाड़ कर रहा हूँ, मुझे एहसास हुआ कि मुझे आवेदन करने, रचना करने आदि कारणों के लिए कार्यों के लिए एक टाइपकास्ट की आवश्यकता है ...

  1. यह एक फ़ंक्शन के प्रतिनिधित्व का इलाज करने के लिए सुविधाजनक हो सकता है जैसे कि यह फ़ंक्शन ही था, ताकि फ़ंक्शन को लागू करना स्पष्ट रूप से एक दुभाषिया का उपयोग करता है, और रचना कार्य एक नया विवरण प्राप्त करता है।

  2. एक बार जब आपके पास फ़ंक्शंस के लिए एक टाइपकास्ट होता है, तो आप विशेष प्रकार के फ़ंक्शंस के लिए टायपेकल प्राप्त कर सकते हैं - मेरे मामले में, मैं इनवर्टेबल फ़ंक्शंस चाहता हूं।

उदाहरण के लिए, पूर्णांक ऑफ़सेट लागू करने वाले कार्यों को एक पूर्णांक युक्त ADT द्वारा दर्शाया जा सकता है। उन कार्यों को लागू करने का अर्थ है पूर्णांक जोड़ना। लिपटे पूर्णांक जोड़कर संरचना को लागू किया जाता है। उलटा फ़ंक्शन में पूर्णांक नकारात्मक है। पहचान समारोह शून्य लपेटता है। निरंतर फ़ंक्शन प्रदान नहीं किया जा सकता है क्योंकि इसके लिए कोई उपयुक्त प्रतिनिधित्व नहीं है।

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

मुझे Data.Function मॉड्यूल मिला , लेकिन कोई टाइपकास्ट नहीं है - बस कुछ सामान्य फ़ंक्शन जो कि Prelude से भी उपलब्ध हैं।

तो - क्यों वहाँ कार्यों के लिए एक टाइपकास्ट नहीं है? क्या यह "सिर्फ इसलिए कि वहाँ" या "नहीं है क्योंकि यह इतना उपयोगी नहीं है जितना आप सोचते हैं"? या शायद विचार के साथ एक मौलिक समस्या है?

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

अधिक सुराग

उदाहरण के लिए कोड दिखाने के लिए कि मैं क्या कर रहा हूँ ...

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}

--  In my first version, Doable only had the one argument f. This version
--  seemed to be needed to support the UndoableOffset type.
--
--  It seems to work, but it also seems strange. In particular,
--  the composition function - a and b are in the class, but c isn't,
--  yet there's nothing special about c compared with a and b.
class Doable f a b where
  fwdApply :: f a b -> a -> b
  compDoable :: f b c -> f a b -> f a c

--  In the first version, I only needed a constraint for
--  Doable f a b, but either version makes sense.
class (Doable f a b, Doable f b a) => Undoable f a b where
  bwd      :: f a b -> f b a

  bwdApply :: f a b -> b -> a
  bwdApply f b = fwdApply (bwd f) b

--  Original ADT - just making sure I could wrap a pair of functions
--  and there were no really daft mistakes.
data UndoableFn a b = UFN { getFwd :: a -> b, getBwd :: b -> a }

instance Doable UndoableFn a b where
  fwdApply = getFwd
  compDoable f g = UFN ((getFwd f) . (getFwd g)) ((getBwd g) . (getBwd f))

instance Undoable UndoableFn a b where
  bwd f    = UFN (getBwd f) (getFwd f)
  bwdApply = getBwd

--  Making this one work led to all the extensions. This representation
--  can only represent certain functions. I seem to need the typeclass
--  arguments, but also to need to restrict which cases can happen, hence
--  the GADT. A GADT with only one constructor still seems odd. Perhaps
--  surprisingly, this type isn't just a toy (except that the whole thing's
--  a toy really) - it's one real case I need for the exercise. Still a
--  simple special case though.
data UndoableOffset a b where
  UOFF :: Int -> UndoableOffset Int Int

instance Doable UndoableOffset Int Int where
  fwdApply (UOFF x) y = y+x
  compDoable (UOFF x) (UOFF y) = UOFF (x+y)

instance Undoable UndoableOffset Int Int where
  bwdApply (UOFF x) y = y-x
  bwd (UOFF x) = UOFF (-x)

--  Some value-constructing functions
--  (-x) isn't shorthand for subtraction - whoops.
undoableAdd :: Int -> UndoableFn Int Int
undoableAdd x = UFN (+x) (\y -> y-x)

undoableMul :: Int -> UndoableFn Int Int
undoableMul x = UFN (*x) (`div` x)

--  With UndoableFn, it's possible to define an invertible function
--  that isn't invertible - to break the laws. To prevent that, need
--  the UFN constructor to be private (and all public ops to preserve
--  the laws). undoableMul is already not always invertible.
validate :: Undoable f a b => Eq a => f a b -> a -> Bool
validate f x = (bwdApply f (fwdApply f x)) == x

--  Validating a multiply-by-zero invertible function shows the flaw
--  in the validate-function plan. Must try harder.
main = do putStrLn . show $ validate (undoableAdd 3) 5
          putStrLn . show $ validate (undoableMul 3) 5
          --putStrLn . show $ validate (undoableMul 0) 5
          fb1 <- return $ UOFF 5
          fb2 <- return $ UOFF 7
          fb3 <- return $ compDoable fb1 fb2
          putStrLn $ "fwdApply fb1  3 = " ++ (show $ fwdApply fb1  3)
          putStrLn $ "bwdApply fb1  8 = " ++ (show $ bwdApply fb1  8)
          putStrLn $ "fwdApply fb3  2 = " ++ (show $ fwdApply fb3  2)
          putStrLn $ "bwdApply fb3 14 = " ++ (show $ bwdApply fb3 14)

आवेदन में एक प्रकार का एकीकरण शामिल है जहां एकीकृत मूल्य समान नहीं हैं, लेकिन उन उल्टे कार्यों के माध्यम से संबंधित हैं - प्रस्तावना-शैली तर्क लेकिन a = f(b)बजाय बाधाओं के साथ a = b। अधिकांश रचना संघ-खोज संरचना के अनुकूलन के परिणामस्वरूप होगी। आक्रमणकारियों की आवश्यकता स्पष्ट होनी चाहिए।

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

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

कारण, मैं आवेदन, मोनाड, तीर आदि का उपयोग नहीं कर सकता

आवेदन और संरचना प्रदान करने के लिए मुख्य संचालन मुझे फ़ंक्शन एब्स्ट्रेक्शन क्लास की आवश्यकता है। यह परिचित लगता है - जैसे Applicative (<*>), Monad (>>=)और Arrow (>>>)सभी रचना कार्य हैं। हालाँकि, मेरे मामले में फ़ंक्शन अमूर्तता को लागू करने वाले प्रकारों में कुछ डेटा संरचना होती है जो एक फ़ंक्शन का प्रतिनिधित्व करती है, लेकिन जो एक फ़ंक्शन नहीं है (और इसमें शामिल नहीं हो सकती है), और जो केवल कुछ सीमित कार्यों का प्रतिनिधित्व कर सकती है।

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

साधारण मामला - जहां मूल "फ़ंक्शन" पूर्णांक-ऑफ़सेट "फ़ंक्शन" तक सीमित हैं, मैं पूर्णांक-ऑफसेट "फ़ंक्शन" के रूप में रचना का परिणाम चाहता हूं - घटक ऑफसेट जोड़ें। यह इस बात का एक बड़ा हिस्सा है कि रचना फ़ंक्शन को क्लास के साथ-साथ एप्लिकेशन फ़ंक्शन में क्यों होना चाहिए।

इसका मतलब है कि मैं संचालन प्रदान नहीं कर सकता pure, returnया arrमेरे प्रकारों के लिए, इसलिए मैं उपयोग नहीं कर सकता Applicative, Monadया Arrow

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

मैं उदाहरण सकता हैCategory । मुझे विश्वास है कि मेरी सभी कार्य-वस्तुएं एक पहचान प्रदान करने में सक्षम होंगी, हालाँकि मुझे इसकी आवश्यकता नहीं है। लेकिन जैसा Categoryकि आवेदन का समर्थन नहीं करता है, मुझे अभी भी उस ऑपरेशन को जोड़ने के लिए एक व्युत्पन्न वर्ग की आवश्यकता होगी।


2
मुझे पागल कहो, लेकिन जब मैं एक टाइपकास्ट के बारे में सोचता हूं, जैसे कि आप यह वर्णन कर रहे हैं कि आवेदन करने और रचना करने के लिए मैं आवेदक फंक्शंस के बारे में सोचता हूं, तो कौन से कार्य हैं। शायद यही वह प्रकार है जिसके बारे में आप सोच रहे हैं?
जिमी होफा

1
मुझे नहीं लगता कि Applicativeयह बहुत सही है - इसमें मानों के साथ-साथ कार्यों को भी लपेटने की आवश्यकता होती है, जबकि मैं केवल कार्यों को लपेटना चाहता हूं, और लिपटे हुए कार्य वास्तव में कार्य हैं, जबकि मेरे लिपटे हुए कार्य सामान्य रूप से नहीं होंगे सबसे सामान्य मामला, वे एएसटी कार्यों का वर्णन कर रहे हैं)। कहाँ <*>प्रकार है f (a -> b) -> f a -> f b, मैं प्रकार के साथ एक आवेदन ऑपरेटर चाहते हैं g a b -> a -> bजहां aऔर bडोमेन निर्दिष्ट और लिपटे समारोह के codomain, लेकिन क्या आवरण अंदर नहीं (जरूरी) कोई वास्तविक कार्य है। तीर पर - संभवतः, मेरी नज़र होगी।
स्टीव ३४

3
यदि आप उलटा चाहते हैं कि एक समूह का मतलब नहीं है?
जे.के.

1
@jk। महान बिंदु, यह महसूस करते हुए कि कार्यों के व्युत्क्रमों को पढ़ने के लिए बहुत सारी चीजें हैं जो ओपी को खोज सकता है कि वह क्या खोज रहा है। यहाँ विषय पर कुछ दिलचस्प पढ़ना बंद है। लेकिन haskell function inverse के लिए एक google बहुत सारी उत्सुक पठन सामग्री देता है। शायद वह सिर्फ डाटा चाहता है। समूह
जिमी

2
@ स्टीव ३१४ मुझे लगा कि रचना के साथ काम करना एक एकल श्रेणी है। यदि डोमेन और कोडोमैन हमेशा समान होते हैं तो वे एक मोनॉयड हैं।
टिम सेगिन

जवाबों:


14

खैर, मुझे ऐसे विचारों का कोई पता नहीं है जो "फ़ंक्शन-वाई" चीजों का प्रतिनिधित्व करने के रूप में खुद को बाजार देते हैं। लेकिन कई ऐसे हैं जो करीब आते हैं

श्रेणियाँ

यदि आपके पास एक साधारण फ़ंक्शन अवधारणा है जिसमें आपके पास एक श्रेणी की तुलना में पहचान और संरचना है।

class Category c where
  id :: c a a
  (.) :: c b c -> c a b -> c a c

नुकसान यह है कि आप वस्तुओं का एक सेट के साथ एक अच्छा श्रेणी उदाहरण नहीं बना सकते है ( a, b, और c)। आप मान सकते हैं कि मैं एक कस्टम श्रेणी वर्ग बना सकता हूँ।

तीर

यदि आपके फ़ंक्शंस में उत्पादों की धारणा है और मनमाने कार्यों को इंजेक्ट कर सकते हैं, तो तीर आपके लिए हैं

 class Arrow a where
   arr :: (b -> c) -> a b c
   first :: a b c -> a (b, d) (c, d)
   second :: a b c -> a (d, b) (d, c)

ArrowApply आवेदन की एक धारणा है जो आप चाहते हैं के लिए महत्वपूर्ण लग रहा है।

Applicatives

आवेदकों के पास आपके आवेदन की धारणा है, मैंने फ़ंक्शन एप्लिकेशन का प्रतिनिधित्व करने के लिए उन्हें एएसटी में उपयोग किया है।

class Functor f => Applicative f where
  pure :: a -> f a
  (<*>) :: f (a -> b) -> f b -> f c

कई अन्य विचार हैं। लेकिन एक सामान्य विषय यह है कि आप अपने फ़ंक्शन का प्रतिनिधित्व करने वाले कुछ डेटा संरचना का निर्माण करें, और एक व्याख्या फ़ंक्शन को पास करने की तुलना में।

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


श्रेणी कमी आवेदन करने के लिए लगता है - ($)। पहली नज़र में तीर बड़े पैमाने पर ओवरकिल की तरह दिखते हैं, लेकिन फिर भी ArrowApplyआशाजनक लगता है - इसलिए जब तक मुझे कुछ भी प्रदान करने की आवश्यकता नहीं है मैं इसे ठीक नहीं कर सकता। इस समय के लिए +1, अधिक जाँच करने के लिए।
213 पर स्टीव 314

3
@ स्टीव 314 श्रेणियों में आवेदन की कमी है, लेकिन भिक्षुओं के पास उन्हें चलाने के लिए एक सार्वभौमिक तरीका नहीं है, इसका मतलब यह नहीं है कि वे उपयोगी नहीं हैं
डैनियल ग्रैज़र

एक आम कारण है कि मैं उपयोग कर सकते हैं नहीं है Applicativeया Arrow(या Monad) - मैं एक सामान्य कार्य रैप नहीं कर सकते हैं (सामान्य रूप में) क्योंकि मेरे प्रकार के मूल्यों का प्रतिनिधित्व एक समारोह लेकिन कर रहे हैं का प्रतिनिधित्व किया डेटा से, और मनमाने ढंग से काम करता है का समर्थन नहीं करेंगे, तो अगर अनुवाद करने का एक तरीका था। इसका मतलब है कि मैं प्रदान नहीं कर सकता pure, arrया returnउदाहरणों के लिए। BTW - वे कक्षाएं उपयोगी हैं, लेकिन मैं उन्हें इस विशेष उद्देश्य के लिए उपयोग नहीं कर सकता। Arrow"बड़े पैमाने पर ओवरकिल" नहीं है - जब मैंने पेपर को पढ़ने की कोशिश की थी, जब मैं इसे समझने के लिए तैयार नहीं था।
स्टीव 314

@ Steve314 डेटा बनाने के लिए एक मोनाड इंटरफ़ेस प्रदान करने का विचार है, जो मुफ्त मोनाड के लिए उपयोग किया जाता है, उन्हें देखें
डैनियल ग्रैज़र

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

2

जैसा कि आप इंगित करते हैं, यहां आवेदक का उपयोग करने के साथ मुख्य समस्या यह है कि इसके लिए कोई समझदार परिभाषा नहीं है pure। इसलिए, Applyआविष्कार किया गया था। कम से कम, यह मेरी समझ है।

दुर्भाग्य से, मेरे पास उदाहरण नहीं हैं कि उदाहरण Applyभी नहीं हैं Applicative। यह दावा किया जाता है कि यह सच है IntMap, लेकिन मुझे पता नहीं क्यों। इसी तरह, मुझे नहीं पता कि आपका उदाहरण - ऑफसेट पूर्णांक - एक Applyउदाहरण मानता है ।


यह एक टिप्पणी की तरह अधिक पढ़ता है, देखें कि कैसे उत्तर देना है
gnat

माफ़ करना। यह कमोबेश मेरा पहला उत्तर है।
user185657

आप कैसे सुझाव देते हैं कि मैं उत्तर में सुधार करूं?
user185657

पाठकों को यह देखने में मदद करने के लिए संपादित करें पर विचार करें कि आपका उत्तर यह कैसे पूछे गए प्रश्न को संबोधित करता है, "कार्यों के लिए एक टाइपकास्ट क्यों नहीं है? क्या यह" सिर्फ इसलिए कि "नहीं है" या "क्योंकि यह आपके विचार से इतना उपयोगी नहीं है" या? विचार के साथ एक मौलिक समस्या है? "
गनत

1
मुझे आशा है कि यह बेहतर है
user185657

1

उल्लेख के अलावा Category, Arrowहै, और Applicative:

मैंने Data.Lambdaकॉनल इलियट द्वारा भी खोजा है:

कुछ फ़ंक्शन जैसी कक्षाएं, लंबोदर जैसे निर्माण

दिलचस्प लगता है, निश्चित रूप से, लेकिन उदाहरण के बिना समझना मुश्किल ...

उदाहरण

उदाहरण मूर्त मूल्यों (टीवी) के बारे में विकी पृष्ठ में पाए जा सकते हैं, जो उन चीजों में से एक हैं जो TypeComposeपुस्तकालय के निर्माण का कारण बनते हैं; देखने के इनपुट और समारोह-मान आउटपुट

टीवी लाइब्रेरी का विचार हैस्केल मूल्यों (कार्यों सहित) को मूर्त तरीके से प्रदर्शित करना है।

स्टैकऑवरफ्लो नियम का पालन करने के लिए नंगे लोंकों को पोस्ट न करने के लिए, मैं नीचे कुछ बिट्स कॉपी करता हूं, जो इन बातों का विचार देना चाहिए:

पहला उदाहरण पढ़ता है:

apples, bananas :: CInput Int
apples  = iTitle "apples"  defaultIn
bananas = iTitle "bananas" defaultIn

shoppingO :: COutput (Int -> Int -> Int)
shoppingO = oTitle "shopping list" $
            oLambda apples (oLambda bananas total)

shopping :: CTV (Int -> Int -> Int)
shopping = tv shoppingO (+)

जो देता है जब चलाने के रूप में runIO shopping(अधिक टिप्पणियों, GUI, और अधिक उदाहरणों के लिए देखें):

shopping list: apples: 8
bananas: 5
total: 13

इस सवाल का पता कैसे पूछा जाता है? देखें कैसे जवाब दें
gnat

@gnat मैंने सोचा था कि Data.Lambdaफ़ंक्शन-जैसी चीज़ों के लिए कक्षाएं देने में परिभाषाएँ (जो कि पूछी गई थीं) ... मुझे यकीन नहीं था कि इन चीजों का उपयोग कैसे किया जाए। मैंने इसकी थोड़ी खोजबीन की। संभवतः, वे हालांकि फ़ंक्शन अनुप्रयोग के लिए एक अमूर्तता प्रदान नहीं करते हैं।
इम्ज़ - इवान ज़खरीशेव
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.