व्याख्यात्मक अंकगणित


9

एक छोटा ज्ञात तथ्य यह है कि यदि आप पर्याप्त भाषा एक्सटेंशन (ghc) को चालू करते हैं तो Haskell एक गतिशील रूप से टाइप की गई भाषा बन जाती है! उदाहरण के लिए निम्नलिखित कार्यक्रम अतिरिक्त लागू करता है।

{-# Language MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, UndecidableInstances #-}

data Zero
data Succ a

class Add a b c | a b -> c
instance Add Zero a a
instance (Add a b c) => Add (Succ a) b (Succ c)

यह वास्तव में किसी भी अधिक हास्केल की तरह नहीं दिखता है। वस्तुओं के संचालन के बजाय, हम प्रकारों पर काम करते हैं। प्रत्येक संख्या यह स्वयं का प्रकार है। कार्यों के बजाय हमारे पास टाइप कक्षाएं हैं। कार्यात्मक निर्भरताएं हमें उन्हें प्रकारों के बीच कार्यों के रूप में उपयोग करने की अनुमति देती हैं।

तो हम अपने कोड को कैसे लागू करते हैं? हम दूसरे वर्ग का उपयोग करते हैं

class Test a | -> a
 where test :: a
instance (Add (Succ (Succ (Succ (Succ Zero)))) (Succ (Succ (Succ Zero))) a)
  => Test a

यह testटाइप 4 + 3 के प्रकार को सेट करता है । यदि हम इसे ghci में खोलते हैं तो हम पाएंगे कि testयह वास्तव में टाइप 7 का है।

Ok, one module loaded.
*Main> :t test
test :: Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))

कार्य

मैं चाहता हूं कि आप एक ऐसा वर्ग लागू करें जो दो पीनो अंकों (गैर-नकारात्मक पूर्णांक) को गुणा करता है। Peano अंकों का निर्माण उपरोक्त उदाहरण में समान डेटा प्रकारों का उपयोग करके किया जाएगा:

data Zero
data Succ a

और आपकी कक्षा का मूल्यांकन भी उसी तरह किया जाएगा जैसा कि ऊपर किया गया है। आप जो चाहें अपनी कक्षा का नाम दे सकते हैं।

आप किसी भी कीमत पर बाइट्स के लिए किसी भी ghc भाषा एक्सटेंशन का उपयोग कर सकते हैं।

परीक्षण के मामलों

ये परीक्षण मामले मान Mलेते हैं कि आपकी कक्षा का नाम है , आप चाहें तो इसे कुछ और नाम दे सकते हैं।

class Test1 a| ->a where test1::a
instance (M (Succ (Succ (Succ (Succ Zero)))) (Succ (Succ (Succ Zero))) a)=>Test1 a

class Test2 a| ->a where test2::a
instance (M Zero (Succ (Succ Zero)) a)=>Test2 a

class Test3 a| ->a where test3::a
instance (M (Succ (Succ (Succ (Succ Zero)))) (Succ Zero) a)=>Test3 a

class Test4 a| ->a where test4::a
instance (M (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))) (Succ (Succ (Succ Zero))) a)=>Test4 a

परिणाम

*Main> :t test1
test1
  :: Succ
       (Succ
          (Succ
             (Succ
                (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))))))))
*Main> :t test2
test2 :: Zero
*Main> :t test3
test3 :: Succ (Succ (Succ (Succ Zero)))
*Main> :t test4
test4
  :: Succ
       (Succ
          (Succ
             (Succ
                (Succ
                   (Succ
                      (Succ
                         (Succ
                            (Succ
                               (Succ
                                  (Succ
                                     (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))))))))))))))

तकनीकी साक्षात्कार टाइपिंग से प्रेरणा मिलती है


क्या भाषा एक्सटेंशन मुफ्त हैं? यदि हां, तो कौन?
आलू ४४

@ आलू 44 अरे हाँ। सभी भाषा एक्सटेंशन मुफ्त हैं।
तदर्थ गार्फ हंटर

1
हे ... यह पोस्ट मेम-वाई लगता है भले ही यह नहीं है।
मैजिक ऑक्टोपस Urn

जवाबों:


9

130 121 बाइट्स

-9 बाइट्स थैंक्स टू अर्जन जोहान्सन

type family a+b where s a+b=a+s b;z+b=b
type family a*b where s a*b=a*b+b;z*b=z
class(a#b)c|a b->c
instance a*b~c=>(a#b)c

इसे ऑनलाइन आज़माएं!

यह अतिरिक्त (+)और गुणा के लिए बंद प्रकार के परिवारों को परिभाषित करता है (*)। फिर एक प्रकार का वर्ग (#)परिभाषित किया गया है जो (*)टाइप परिवार के साथ टाइप अकाल की दुनिया से टाइपकास्टल प्रोलॉग की दुनिया में बदलने के लिए टाइप परिवार का उपयोग करता है ।


3
आप समीकरणों स्वैप हैं, तो आप की जगह ले सकता Zeroसे z
अर्जन जोहान्सन

1
@ ØrrrJohansen किया। मैं किसी के लिए 9 बाइट बचाता हूं और मेरे लिए 9 बाइट बचता है।
आलू ४०

मैं नहीं जानता कि कैसे टाइप परिवारों का उपयोग किया जाए, लेकिन शायद इस तरह का एक फ़ंक्शन ताकि आपको परिभाषित करने की आवश्यकता न हो +, उपयोगी है?
लिन

@ लियोन जो लंबे समय तक समाप्त होता है। TIO
पोटेटो44

1
@WheatWizard को मुझे बस एहसास हुआ कि मैंने जिस कोड को टिप्पणी में पोस्ट किया है क्योंकि यह लंबे समय तक निकलता है, अनिवार्य रूप से आपके उत्तर का पूंछ पुनरावर्ती संस्करण है।
आलू 13

6

139 बाइट्स

class(a+b)c|a b->c;instance(Zero+a)a;instance(a+b)c=>(s a+b)(s c)
class(a*b)c|a b->c;instance(Zero*a)Zero;instance((a*b)c,(b+c)d)=>(s a*b)d

इसे ऑनलाइन आज़माएं!

एक प्रकार के ऑपरेटर को परिभाषित करता है *। प्रोलोग कार्यक्रम के समतुल्य:

plus(0, A, A).
plus(s(A), B, s(C)) :- plus(A, B, C).
mult(0, _, 0).
mult(s(A), B, D) :- mult(A, B, C), plus(B, C, D).

आलू और हैट विज़ार्ड ने 9 बाइट्स बचाए। धन्यवाद!


आपको अपनी डेटा घोषणाओं को अपने बाइट कुल में गिनने की आवश्यकता नहीं है। जब मुझे मौका मिले तो मैं इस प्रश्न को स्पष्ट कर
दूंगा

इसके अलावा, मुझे लगता है कि आप इसके fबजाय एक सामान्य का उपयोग कर सकते हैं Succ
तदर्थ गार्फ हंटर

1
आप कॉलन को डिच करके 9 बाइट्स बचा सकते हैं।
आलू ४४

मुझे लगता है कि हैट विजार्ड ने भी 9 को बचाया, 6. 6. सक्सेस की तीन घटनाएं नहीं हुईं।
आलू ४०

1

परिवार-संस्करण, 115 बाइट्स

type family(a%b)c where(a%b)(s c)=s((a%b)c);(s a%b)z=(a%b)b;(z%b)z=z
class(a#b)c|a b->c
instance(a%b)Zero~c=>(a#b)c

इसे ऑनलाइन आज़माएं!

यह आलू की तरह बंद परिवार का उपयोग करता है । अन्य उत्तर के विपरीत मैं केवल 1 प्रकार के परिवार का उपयोग करता हूं।

type family(a%b)c where
  -- If the accumulator is Succ c:
  -- the answer is Succ of the answer if the accumulator were c
  (a%b)(s c)=s((a%b)c)
  -- If the left hand argument is Succ a, and the right hand is b
  -- the result is the result if the left were a and the accumulator were b
  (s a%b)z=(a%b)b
  -- If the left hand argument is zero
  -- the result is zero
  (z%b)z=z

यह एक ऑपरेटर को तीन प्रकारों पर परिभाषित करता है। यह अनिवार्य रूप से लागू होता है (a*b)+c। जब भी हम अपने दाहिने हाथ के तर्क को कुल में जोड़ना चाहते हैं तो हम इसे संचायक में डालते हैं।

यह हमें (+)सभी को परिभाषित करने की आवश्यकता से रोकता है । तकनीकी रूप से आप इस परिवार का उपयोग करने के अलावा जोड़कर कर सकते हैं

class Add a b c | a b -> c
instance (Succ Zero % a) b ~ c => Add a b c

क्लास-वर्जन, 137 बाइट्स

class(a#b)c d|a b c->d
instance(a#b)c d=>(a#b)(f c)(f d)
instance(a#b)b d=>(f a#b)Zero d
instance(Zero#a)Zero Zero
type(a*b)c=(a#b)Zero c

इसे ऑनलाइन आज़माएं!

यह वर्ग संस्करण पारिवारिक संस्करण के लिए कुछ जमीन खो देता है, हालांकि यह अभी भी सबसे छोटे वर्ग संस्करण से छोटा है। यह मेरे पारिवारिक संस्करण के समान दृष्टिकोण का उपयोग करता है।


अच्छा, मैं देख रहा हूं कि आपका प्रकार परिवार गणितीय रूप से * b + c लागू कर रहा है। क्या "विभाजन" का उल्लेख "जोड़" करने के लिए है?
11:44 बजे आलू

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

@ आलू ४४ मैं इस धारणा के तहत था कि एक वर्ग केवल एक तरह से कुछ होता है जिसके परिणामस्वरूप एक गर्भनिरोधक होता है। शायद यह सवाल में स्पष्टता की कमी के कारण था। मैं अपने 115 उत्तर पर वापस लौटूंगा।
तदर्थ गार्फ हंटर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.