शुद्ध कार्यात्मक भाषाओं में, क्या उलटा कार्य करने के लिए एक एल्गोरिथ्म है?


100

हास्केल जैसी शुद्ध कार्यात्मक भाषाओं में, क्या किसी फ़ंक्शन के व्युत्क्रम को प्राप्त करने के लिए एक एल्गोरिथ्म है, (जब यह जीवनात्मक है)? और क्या आपके कार्य को प्रोग्राम करने का कोई विशिष्ट तरीका है तो यह है?


5
गणितीय रूप से यह कहना गलत नहीं है कि, के मामले में f x = 1, 1 का विलोम पूर्णांकों का एक सेट है और किसी अन्य चीज का व्युत्क्रम एक खाली सेट है। इसके बावजूद कि कुछ जवाब क्या कहते हैं, फ़ंक्शन का विशेषण नहीं होना सबसे बड़ी समस्या नहीं है।
कारोलिस जुओदेलो

2
सही प्रतिक्रिया हां है, लेकिन यह कुशल नहीं है। F: A -> B और A परिमित है, तो, b € B को देखते हुए, आपको "केवल" को सभी f (A) का निरीक्षण करना होगा, ताकि सभी a € A का पता लगाया जा सके f (a) = b। क्वांटम कंप्यूटर में, शायद O (आकार (a)) जटिलता होगी। बेशक, आप एक व्यावहारिक एल्गोरिदम की तलाश करते हैं। यह (ओ (2 ^ आकार (ए)) है) नहीं है, लेकिन मौजूद है ...
जॉजुआन

क्विकचेक यह बिल्कुल कर रहा है (वे f: A -> बूल में एक गलत की तलाश करते हैं)।
२१

4
@ करोलिसजुॉडेलो: मैं असहमत हूं; आमतौर पर इसका मतलब उलटा नहीं होता है। हर बार जब मैं इस शब्द का सामना करता हूं, तो इसका उलटा fएक gऐसा कार्य होता है जैसे f . g = idऔर g . f = id। आपका उम्मीदवार उस मामले में भी टाइपकास्ट नहीं करता है।
बेन मिलवुड

3
@BenMillwood, आप सही कह रहे हैं। मैंने जो कहा, उसे प्रतिलोम छवि कहा जाता है, विलोम क्रिया नहीं। मेरा कहना यह था कि जिन उत्तरों f x = 1का कोई उलटा नहीं है, वे बहुत संकीर्ण दृष्टिकोण रखते हैं और समस्या की पूरी जटिलता को अनदेखा करते हैं।
कारोलिस जुओदेलो

जवाबों:


101

कुछ मामलों में, हाँ! निःशुल्क के लिए Bidirectionalization नामक एक सुंदर पेपर है ! जो कुछ मामलों पर चर्चा करता है - जब आपका कार्य पर्याप्त रूप से बहुरूपिक होता है - जहां यह संभव है, पूरी तरह से स्वचालित रूप से एक अदृश्य कार्य प्राप्त करने के लिए। (यह भी चर्चा करता है कि जब कार्य बहुरूपी नहीं है तो समस्या क्या है।

जिस मामले में आपका फ़ंक्शन उलटा है, उससे उलटा है (उलटा इनपुट के साथ); अन्य मामलों में, आपको एक फ़ंक्शन मिलता है जो एक पुराने इनपुट मूल्य और एक नए आउटपुट मूल्य को "मर्ज" करने की कोशिश करता है।


3
यहां एक और हालिया पेपर है जो द्विदिश में कला की स्थिति का सर्वेक्षण करता है। इसमें तकनीकों के तीन परिवार शामिल हैं, जिसमें "सिंटैक्टिक" और कॉम्बिनेटर आधारित दृष्टिकोण भी शामिल हैं: iai.uni-bonn.de/~jv/ssgip-bidirectional-final.pdf
sclv

और सिर्फ उल्लेख करने के लिए, 2008 में यह संदेश था-कैफे के लिए, putकिसी भी रिकॉर्ड संरचनाओं में काम करने के लिए अशुभ हैक के लिए एक दुष्ट हैक के साथ Data: haskell.org/pipermail/haskell-cafe/2008-April/0420003.html एक दृष्टिकोण का उपयोग करके बाद में "मुफ्त में" (अधिक कठोर, अधिक सामान्यतः, अधिक राजसी, आदि) प्रस्तुत किया।
sclv

यह 2017 है और निश्चित रूप से पेपर का लिंक अब मान्य नहीं है, यहाँ अपडेट किया गया है: pdfs.semanticscholar.org/5f0d/…
मीना गेब्रियल

37

नहीं, यह सामान्य रूप से संभव नहीं है।

प्रमाण: प्रकार के जीव विशेष कार्यों पर विचार करें

type F = [Bit] -> [Bit]

साथ में

data Bit = B0 | B1

मान लें कि हमारे पास ऐसा इन्वर्टर inv :: F -> Fहै inv f . f ≡ id। मान लें कि हमने f = idइसकी पुष्टि के लिए इसे फ़ंक्शन के लिए परीक्षण किया है

inv f (repeat B0) -> (B0 : ls)

चूँकि यह B0उत्पादन में पहले कुछ परिमित समय के बाद आया होगा, हमारे पास nदोनों गहराई पर एक ऊपरी सीमा है जो invवास्तव में इस परिणाम को प्राप्त करने के लिए हमारे परीक्षण इनपुट का मूल्यांकन किया था, साथ ही साथ इसे कितनी बार कॉल किया जा सकता है f। अब कार्यों के एक परिवार को परिभाषित करें

g j (B1 : B0 : ... (n+j times) ... B0 : ls)
   = B0 : ... (n+j times) ... B0 : B1 : ls
g j (B0 : ... (n+j times) ... B0 : B1 : ls)
   = B1 : B0 : ... (n+j times) ... B0 : ls
g j l = l

स्पष्ट रूप से, सभी के लिए 0<j≤n, g jएक आक्षेप है, वास्तव में आत्म-उलटा। इसलिए हमें पुष्टि करने में सक्षम होना चाहिए

inv (g j) (replicate (n+j) B0 ++ B1 : repeat B0) -> (B1 : ls)

लेकिन इसे पूरा करने के लिए, inv (g j)या तो आवश्यक होगा

  • की g j (B1 : repeat B0)गहराई तक मूल्यांकन करेंn+j > n
  • head $ g j lकम से कम nविभिन्न सूचियों के मिलान के लिए मूल्यांकन करेंreplicate (n+j) B0 ++ B1 : ls

उस बिंदु तक, कम से कम एक से g jअप्रभेद्य है f, और चूंकि inv fइनमें से कोई भी मूल्यांकन नहीं किया था, invसंभवतः इसे अलग नहीं बता सकता था - अपने आप पर कुछ रनटाइम-माप करने का छोटा, जो केवल संभव है IO Monad

                                                                                                                                   ⬜


19

आप इसे विकिपीडिया पर देख सकते हैं, इसे प्रतिवर्ती कम्प्यूटिंग कहा जाता है ।

सामान्य तौर पर आप इसे नहीं कर सकते हैं और कार्यात्मक भाषाओं में से कोई भी विकल्प नहीं है। उदाहरण के लिए:

f :: a -> Int
f _ = 1

इस फ़ंक्शन में एक व्युत्क्रम नहीं है।


1
क्या यह कहना गलत होगा कि fइसका उलटा है, यह सिर्फ इतना है कि व्युत्क्रम एक गैर-नियतात्मक कार्य है?
मैट फेनविक

10
@MattFenwick उदाहरण के लिए हास्केल जैसी भाषाओं में, फ़ंक्शंस केवल नोंडेटर्मिनिस्टिक (प्रकारों को बदलने और आपके उपयोग करने के तरीके के बिना) नहीं हैं। कोई भी हास्केल फ़ंक्शन मौजूद नहीं है, g :: Int -> aजिसका व्युत्क्रम है f, भले ही आप fगणितीय रूप से व्युत्क्रम का वर्णन कर सकते हैं ।
बेन

2
@ मैट: कार्यात्मक प्रोग्रामिंग और तर्क में "नीचे" देखें। एक "निचला" एक "असंभव" मूल्य है, या तो क्योंकि यह विरोधाभासी है, गैर-समाप्तिकारी है, या एक अनिर्दिष्ट समस्या का समाधान है (यह केवल विरोधाभासी से अधिक है - हम एक डिजाइन का पता लगाने के लिए एक समाधान को "पीछा" कर सकते हैं। अंतरिक्ष "अपरिभाषित" और "त्रुटि" का उपयोग विकास के दौरान)। एक "नीचे" x में टाइप ए है। यह हर प्रकार का "मूल्य" (या "मूल्य") है। यह एक तार्किक विरोधाभास है, क्योंकि प्रकार प्रस्ताव हैं और ऐसा कोई मूल्य नहीं है जो हर प्रस्ताव को संतुष्ट करता हो। अच्छा विचार विमर्श के लिए हास्केल-कैफे पर देखो
nomen

2
@ मैट: गैर-नियतत्ववाद के संदर्भ में आक्रमणकारियों के गैर-अस्तित्व की विशेषता के बजाय, किसी को इसे बॉटम के संदर्भ में चिह्नित करना चाहिए। F _ = 1 का व्युत्क्रम नीचे है, क्योंकि इसमें हर प्रकार का निवास होना चाहिए (वैकल्पिक रूप से, यह नीचे है क्योंकि f में किसी एकल प्रकार से अधिक के साथ किसी भी प्रकार के लिए कोई उलटा कार्य नहीं है - जिस पहलू पर आपने ध्यान केंद्रित किया है, मुझे लगता है)। नीचे होने के नाते सकारात्मक और नकारात्मक दोनों को लिया जा सकता है क्योंकि मूल्यों के बारे में जोर दिया जाता है। कोई समझदारी से "मूल्य" के नीचे होने के रूप में एक मनमाने ढंग से कार्य के व्युत्क्रम की बात कर सकता है। (हालांकि यह नहीं है "वास्तव में" एक मूल्य)
nomen

1
बहुत बाद में यहां वापस भटकने के बाद, मुझे लगता है कि मैं देख रहा हूं कि मैट पर क्या हो रहा है: हम अक्सर सूचियों के माध्यम से नॉनडेटर्मिनिज़म का मॉडल बनाते हैं, और हम आक्रमणकारियों के लिए भी ऐसा कर सकते हैं। चलो उलटा f x = 2 * xहोने दो f' x = [x / 2], और फिर उलटा f _ = 1है f' 1 = [minBound ..]; f' _ = []। यही है, 1 के लिए कई व्युत्क्रम हैं, और किसी भी अन्य मूल्य के लिए नहीं।
अमलियॉ

16

अधिकांश कार्यात्मक भाषाओं में नहीं, लेकिन तर्क प्रोग्रामिंग या संबंधपरक प्रोग्रामिंग में, आपके द्वारा परिभाषित अधिकांश फ़ंक्शन वास्तव में कार्य नहीं बल्कि "संबंध" हैं, और ये दोनों दिशाओं में उपयोग किए जा सकते हैं। उदाहरण के लिए देखें प्रोलॉग या कैरेन।


1
या बुध , जो अन्यथा हास्केल की भावना का एक बहुत कुछ साझा करता है। - अच्छी बात, +1।
लेफ्टरनैबाउट

11

इस तरह के कार्य लगभग हमेशा अनिर्णायक होते हैं। आपके पास कुछ विशिष्ट कार्यों के लिए एक समाधान हो सकता है, लेकिन सामान्य रूप से नहीं।

यहां, आप यह भी नहीं पहचान सकते हैं कि किन कार्यों में उलटा है। बारटिंगग्राम, एचपी द लैंबडा कैलकुलस का उद्धरण : इसके सिंटैक्स और शब्दार्थ। नॉर्थ हॉलैंड, एम्स्टर्डम (1984) :

लंबोदर-पदों का एक सेट अगर यह न तो खाली है और न ही पूरा सेट है। यदि A और B दो nontrivial हैं, तो लैम्बडा-टर्म्स ऑफ (बीटा) समानता के तहत सेट के असंतुष्ट सेट, तो A और B पुनरावर्ती अविभाज्य हैं।

आइए A को लैम्ब्डा शब्दों के सेट के रूप में लें जो कि इनवर्टेड फ़ंक्शंस का प्रतिनिधित्व करते हैं और बाकी बी। दोनों गैर-रिक्त हैं और बीटा समानता के तहत बंद हैं। इसलिए यह तय करना संभव नहीं है कि कोई फ़ंक्शन उलटा है या नहीं।

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


11

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

आप जो करना चाहते हैं, वह डोमेन के तत्वों के माध्यम से चलाया जाता है और देखें कि क्या वे उस श्रेणी के तत्व के बराबर हैं, जिसे आप उल्टा करने की कोशिश कर रहे हैं, और जो काम करता है उसे पहले करें:

inv :: Eq b => [a] -> (a -> b) -> (b -> a)
inv domain f b = head [ a | a <- domain, f a == b ]

चूंकि आपने कहा है कि fयह एक आपत्ति है, इसलिए केवल एक और ऐसा एक ही तत्व होना चाहिए। चाल, निश्चित रूप से, यह सुनिश्चित करना है कि डोमेन की आपकी गणना वास्तव में सभी तत्वों तक सीमित समय में पहुंचती है । आप से एक द्विभाजन को उलटने की कोशिश कर रहे हैं Integerकरने के लिए Integer, का उपयोग कर [0,1 ..] ++ [-1,-2 ..]काम नहीं करेगा आप ऋणात्मक संख्याओं के लिए कभी नहीं मिलेगा के रूप में। लगातार, inv ([0,1 ..] ++ [-1,-2 ..]) (+1) (-3)कभी भी मूल्य नहीं मिलेगा।

हालाँकि, 0 : concatMap (\x -> [x,-x]) [1..]काम करेगा, क्योंकि यह निम्न क्रम में पूर्णांकों के माध्यम से चलता है [0,1,-1,2,-2,3,-3, and so on]। वास्तव में inv (0 : concatMap (\x -> [x,-x]) [1..]) (+1) (-3)तुरंत रिटर्न -4!

नियंत्रणमोनाडओमेगा पैकेज एक अच्छे तरीके से ट्यूपल्स वगैरह की सूचियों के माध्यम से चलाने में आपकी सहायता कर सकता है; मुझे यकीन है कि इस तरह और भी पैकेज हैं - लेकिन मैं उन्हें नहीं जानता।


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

(चेतावनी: अनुपलब्ध कोड इस प्रकार है)

तो क्या आप Bijectionप्रकार aऔर के बीच में से एक डेटा टाइप परिभाषित कर सकते हैं b:

data Bi a b = Bi {
    apply :: a -> b,
    invert :: b -> a 
}

कई स्थिरांक के साथ (जहाँ आप कह सकते हैं कि 'मुझे पता है कि वे पूर्वाग्रह हैं!') जैसे आप चाहते हैं, जैसे:

notBi :: Bi Bool Bool
notBi = Bi not not

add1Bi :: Bi Integer Integer
add1Bi = Bi (+1) (subtract 1)

और स्मार्ट कॉम्बीनेटरों की एक जोड़ी, जैसे:

idBi :: Bi a a 
idBi = Bi id id

invertBi :: Bi a b -> Bi b a
invertBi (Bi a i) = (Bi i a)

composeBi :: Bi a b -> Bi b c -> Bi a c
composeBi (Bi a1 i1) (Bi a2 i2) = Bi (a2 . a1) (i1 . i2)

mapBi :: Bi a b -> Bi [a] [b]
mapBi (Bi a i) = Bi (map a) (map i)

bruteForceBi :: Eq b => [a] -> (a -> b) -> Bi a b
bruteForceBi domain f = Bi f (inv domain f)

मुझे लगता है कि आप तब कर सकते हैं invert (mapBi add1Bi) [1,5,6]और प्राप्त कर सकते हैं [0,4,5]। यदि आप अपने कॉम्बीनेटरों को स्मार्ट तरीके से चुनते हैं, तो मुझे लगता है कि आपको Biहाथ से लगातार लिखने की संख्या काफी सीमित हो सकती है।

आखिरकार, यदि आप जानते हैं कि कोई फ़ंक्शन एक आपत्ति है, तो आपको उम्मीद है कि आपके सिर में उस तथ्य का एक प्रूफ-स्केच होगा, जिसे करी-हावर्ड समरूपता एक कार्यक्रम में बदलने में सक्षम होना चाहिए :-)


6

मैं हाल ही में इस तरह के मुद्दों के साथ काम कर रहा हूं, और नहीं, मैं कहूंगा कि (ए) यह कई मामलों में मुश्किल नहीं है, लेकिन (बी) यह बिल्कुल भी कुशल नहीं है।

मूल रूप से, मान लीजिए कि आपके पास है f :: a -> b, और fयह वास्तव में एक द्विज है। आप उलटे की गणना f' :: b -> aवास्तव में गूंगे तरीके से कर सकते हैं:

import Data.List

-- | Class for types whose values are recursively enumerable.
class Enumerable a where
    -- | Produce the list of all values of type @a@.
    enumerate :: [a]

 -- | Note, this is only guaranteed to terminate if @f@ is a bijection!
invert :: (Enumerable a, Eq b) => (a -> b) -> b -> Maybe a
invert f b = find (\a -> f a == b) enumerate

यदि fएक आक्षेप है और enumerateवास्तव में सभी मूल्यों का उत्पादन करता है a, तो आप अंततः एक aऐसा हिट करेंगे f a == b

एक प्रकार Boundedऔर एक Enumउदाहरण है जो तुच्छ रूप से बनाया जा सकता है RecursivelyEnumerableEnumerableप्रकार के जोड़े भी बनाए जा सकते हैं Enumerable:

instance (Enumerable a, Enumerable b) => Enumerable (a, b) where
    enumerate = crossWith (,) enumerate enumerate

crossWith :: (a -> b -> c) -> [a] -> [b] -> [c]
crossWith f _ [] = []
crossWith f [] _ = []
crossWith f (x0:xs) (y0:ys) =
    f x0 y0 : interleave (map (f x0) ys) 
                         (interleave (map (flip f y0) xs)
                                     (crossWith f xs ys))

interleave :: [a] -> [a] -> [a]
interleave xs [] = xs
interleave [] ys = []
interleave (x:xs) ys = x : interleave ys xs

समान Enumerableप्रकार के विघटन के लिए जाता है :

instance (Enumerable a, Enumerable b) => Enumerable (Either a b) where
    enumerate = enumerateEither enumerate enumerate

enumerateEither :: [a] -> [b] -> [Either a b]
enumerateEither [] ys = map Right ys
enumerateEither xs [] = map Left xs
enumerateEither (x:xs) (y:ys) = Left x : Right y : enumerateEither xs ys

तथ्य यह है कि हम यह दोनों के लिए कर सकते हैं (,)और Eitherशायद इसका मतलब है कि हम इसे किसी भी बीजीय डेटा प्रकार के लिए कर सकते हैं।


5

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


13
किसी भी क्रिप्टोसिस्टम (कुछ अजीब लोगों को छोड़कर, जैसे एक समय के पैड, जो अन्य कारणों से अनसुनी कर रहे हैं) को क्रूर बल द्वारा क्रैक किया जा सकता है। यह उन्हें किसी भी कम उपयोगी नहीं बनाता है, और न ही एक अव्यवहारिक रूप से महंगा उलटा कार्य होगा।

क्या यह वास्तव में है? यदि आप एक एन्क्रिप्शन फ़ंक्शन के बारे में सोचते हैं, String encrypt(String key, String text)तो कुंजी के बिना आप अभी भी कुछ नहीं कर पाएंगे। EDIT: इसके अलावा डेलन ने क्या कहा।
mck

@MaciekAlbin आपके हमले के मॉडल पर निर्भर करता है। उदाहरण के लिए चुना प्लेनटेक्स्ट हमलों, कुंजी को निकालने की अनुमति दे सकता है, जो तब उस कुंजी के साथ एन्क्रिप्ट किए गए अन्य सिफर ग्रंथों पर हमला करने की अनुमति देगा।

"संभव" से मेरा अभिप्राय था, ऐसा कुछ जो किसी भी उचित समय में किया जा सके। मेरा मतलब "अभिकलन" नहीं है (मुझे पूरा यकीन है)।
जेफरी स्कोफिल्ड

@JeffreyScofield मैं आपकी बात देखता हूं। लेकिन मुझे कहना है, मैं "सिद्धांत में व्यवहार्य" से भ्रमित हूं - (हमारी परिभाषा) व्यवहार्यता केवल यह नहीं बताती है कि व्यावहारिक रूप से कितना कठिन है?

5

कुछ मामलों में, इसे एक प्रतीकात्मक प्रतिनिधित्व में परिवर्तित करके एक विशेषण फ़ंक्शन के व्युत्क्रम को खोजना संभव है। इस उदाहरण के आधार पर , मैंने कुछ सरल बहुपद कार्यों के व्युत्क्रमों को खोजने के लिए यह हास्केल कार्यक्रम लिखा:

bijective_function x = x*2+1

main = do
    print $ bijective_function 3
    print $ inverse_function bijective_function (bijective_function 3)

data Expr = X | Const Double |
            Plus Expr Expr | Subtract Expr Expr | Mult Expr Expr | Div Expr Expr |
            Negate Expr | Inverse Expr |
            Exp Expr | Log Expr | Sin Expr | Atanh Expr | Sinh Expr | Acosh Expr | Cosh Expr | Tan Expr | Cos Expr |Asinh Expr|Atan Expr|Acos Expr|Asin Expr|Abs Expr|Signum Expr|Integer
       deriving (Show, Eq)

instance Num Expr where
    (+) = Plus
    (-) = Subtract
    (*) = Mult
    abs = Abs
    signum = Signum
    negate = Negate
    fromInteger a = Const $ fromIntegral a

instance Fractional Expr where
    recip = Inverse
    fromRational a = Const $ realToFrac a
    (/) = Div

instance Floating Expr where
    pi = Const pi
    exp = Exp
    log = Log
    sin = Sin
    atanh = Atanh
    sinh = Sinh
    cosh = Cosh
    acosh = Acosh
    cos = Cos
    tan = Tan
    asin = Asin
    acos = Acos
    atan = Atan
    asinh = Asinh

fromFunction f = f X

toFunction :: Expr -> (Double -> Double)
toFunction X = \x -> x
toFunction (Negate a) = \a -> (negate a)
toFunction (Const a) = const a
toFunction (Plus a b) = \x -> (toFunction a x) + (toFunction b x)
toFunction (Subtract a b) = \x -> (toFunction a x) - (toFunction b x)
toFunction (Mult a b) = \x -> (toFunction a x) * (toFunction b x)
toFunction (Div a b) = \x -> (toFunction a x) / (toFunction b x)


with_function func x = toFunction $ func $ fromFunction x

simplify X = X
simplify (Div (Const a) (Const b)) = Const (a/b)
simplify (Mult (Const a) (Const b)) | a == 0 || b == 0 = 0 | otherwise = Const (a*b)
simplify (Negate (Negate a)) = simplify a
simplify (Subtract a b) = simplify ( Plus (simplify a) (Negate (simplify b)) )
simplify (Div a b) | a == b = Const 1.0 | otherwise = simplify (Div (simplify a) (simplify b))
simplify (Mult a b) = simplify (Mult (simplify a) (simplify b))
simplify (Const a) = Const a
simplify (Plus (Const a) (Const b)) = Const (a+b)
simplify (Plus a (Const b)) = simplify (Plus (Const b) (simplify a))
simplify (Plus (Mult (Const a) X) (Mult (Const b) X)) = (simplify (Mult (Const (a+b)) X))
simplify (Plus (Const a) b) = simplify (Plus (simplify b) (Const a))
simplify (Plus X a) = simplify (Plus (Mult 1 X) (simplify a))
simplify (Plus a X) = simplify (Plus (Mult 1 X) (simplify a))
simplify (Plus a b) = (simplify (Plus (simplify a) (simplify b)))
simplify a = a

inverse X = X
inverse (Const a) = simplify (Const a)
inverse (Mult (Const a) (Const b)) = Const (a * b)
inverse (Mult (Const a) X) = (Div X (Const a))
inverse (Plus X (Const a)) = (Subtract X (Const a))
inverse (Negate x) = Negate (inverse x)
inverse a = inverse (simplify a)

inverse_function x = with_function inverse x

यह उदाहरण केवल अंकगणितीय अभिव्यक्तियों के साथ काम करता है, लेकिन यह संभव है कि सूचियों के साथ भी काम किया जा सके।


4

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

f x = 1

आपका कार्य एक स्थिरांक है, यहाँ यह जीव विशेष कार्यों के बारे में है।
सोइल - मैथ्यू प्रेवोट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.