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