पैटर्न के अलावा, हास्केल में और क्या हो सकता है?


15

मैं वर्तमान में हास्केल का अध्ययन कर रहा हूं और एक परियोजना को समझने की कोशिश करता हूं जो क्रिप्टोग्राफिक एल्गोरिदम को लागू करने के लिए हास्केल का उपयोग करता है। ऑनलाइन लर्न यू हास्केल फॉर ग्रेट गुड पढ़ने के बाद , मैं उस परियोजना के कोड को समझना शुरू करता हूं। तब मैंने पाया कि मैं "@" प्रतीक के साथ निम्न कोड पर अटक गया हूं:

-- | Generate an @n@-dimensional secret key over @rq@.
genKey :: forall rq rnd n . (MonadRandom rnd, Random rq, Reflects n Int)
       => rnd (PRFKey n rq)
genKey = fmap Key $ randomMtx 1 $ value @n

यहाँ randomMtx को निम्नानुसार परिभाषित किया गया है:

-- | A random matrix having a given number of rows and columns.
randomMtx :: (MonadRandom rnd, Random a) => Int -> Int -> rnd (Matrix a)
randomMtx r c = M.fromList r c <$> replicateM (r*c) getRandom

और PRFKey नीचे परिभाषित किया गया है:

-- | A PRF secret key of dimension @n@ over ring @a@.
newtype PRFKey n a = Key { key :: Matrix a }

सभी सूचना स्रोत मैं कह सकता हूं कि @ जैसा कि पैटर्न है, लेकिन कोड का यह टुकड़ा स्पष्ट रूप से ऐसा नहीं है। मैंने https://www.haskell.org/definition/haskell2010.pdf पर ऑनलाइन ट्यूटोरियल, ब्लॉग और यहां तक कि हास्केल 2010 भाषा की रिपोर्ट की जांच की है । इस सवाल का कोई जवाब नहीं है।

इस तरह से @ का उपयोग करते हुए इस परियोजना में अधिक कोड स्निपेट मिल सकते हैं:

-- | Generate public parameters (\( \mathbf{A}_0 \) and \(
-- \mathbf{A}_1 \)) for @n@-dimensional secret keys over a ring @rq@
-- for gadget indicated by @gad@.
genParams :: forall gad rq rnd n .
            (MonadRandom rnd, Random rq, Reflects n Int, Gadget gad rq)
          => rnd (PRFParams n gad rq)
genParams = let len = length $ gadget @gad @rq
                n   = value @n
            in Params <$> (randomMtx n (n*len)) <*> (randomMtx n (n*len))

मैं इस पर किसी भी मदद की गहराई से सराहना करता हूं।


11
ये टाइप एप्लीकेशन हैंइस प्रश्नोत्तर को भी देखें । आप उस कमेट को भी देख सकते हैं जिसने उन्हें कोड में पेश किया था।
मिकेलएफ

लिंक के लिए बहुत बहुत धन्यवाद! ये वही हैं जिसकी मुझे तलाश है। हैरानी की बात है, आप भी कोड की प्रतिबद्ध पहचान! इसके लिए बहुत धन्यवाद। बस आप इस बारे में उत्सुक हैं कि आप इसे कैसे खोजते हैं? @ मिकेलफ
सिगुरडब्लू

2
गिटब के पास दोष देने के लिए अपना स्वयं का इंटरफ़ेस है , जो आपको बताएगा कि प्रत्येक पंक्ति में कौन सा प्रतिबद्ध अंतिम रूप से संशोधित किया गया था।
MikaelF

इस उपयोगी टिप के लिए बहुत बहुत धन्यवाद :)
SigurdW

1
@MichaelLitchard बहुत खुशी है कि आप इससे लाभ उठा सकते हैं। मैं दयालु लोगों का आभारी हूं कि उन्होंने मुझे मदद करने के लिए समय बिताया। आशा है कि उत्तर भी दूसरों की मदद कर सकता है।
सिगर्डडब्ल्यू

जवाबों:


16

उस @n आधुनिक हास्केल की एक उन्नत विशेषता है, जिसे आमतौर पर LYAH जैसे ट्यूटोरियल द्वारा कवर नहीं किया जाता है, और न ही रिपोर्ट पाया जा सकता है।

इसे एक प्रकार का एप्लिकेशन कहा जाता है और यह जीएचसी भाषा एक्सटेंशन है। इसे समझने के लिए, इस सरल बहुरूपी फ़ंक्शन पर विचार करें

dup :: forall a . a -> (a, a)
dup x = (x, x)

सहज dupरूप से कॉलिंग कार्य इस प्रकार है:

  • फोन करने वाले एक चुनता प्रकार a
  • फोन करने वाले एक चुनता मूल्य x पहले से चुना प्रकार कीa
  • dup फिर प्रकार के मूल्य के साथ उत्तर देता है (a,a)

एक अर्थ में, dupदो तर्क लेता है: प्रकार aऔर मूल्य x :: a। हालांकि, जीएचसी आमतौर पर टाइप करने में सक्षम होता है a(उदाहरण के लिए x, या उस संदर्भ से जहां हम उपयोग कर रहे हैं dup), इसलिए हम आम तौर पर केवल एक तर्क पास करते dupहैं x। उदाहरण के लिए, हमारे पास है

dup True    :: (Bool, Bool)
dup "hello" :: (String, String)
...

अब, क्या होगा अगर हम aस्पष्ट रूप से पारित करना चाहते हैं ? ठीक है, उस स्थिति में हम TypeApplicationsएक्सटेंशन को चालू कर सकते हैं , और लिख सकते हैं

dup @Bool True      :: (Bool, Bool)
dup @String "hello" :: (String, String)
...

@...प्रकारों को मानने वाले तर्कों पर ध्यान दें (मूल्यों पर नहीं)। वे कुछ हैं जो संकलित समय पर मौजूद हैं, केवल - रनटाइम पर तर्क मौजूद नहीं है।

हम ऐसा क्यों चाहते हैं? खैर, कभी-कभी कोई xआस-पास नहीं होता है, और हम संकलक को सही चुनने के लिए उकसाना चाहते हैं a। उदाहरण के लिए

dup @Bool   :: Bool -> (Bool, Bool)
dup @String :: String -> (String, String)
...

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

अब, अपने विशिष्ट मामले के बारे में। मेरे पास सभी विवरण नहीं हैं, मैं पुस्तकालय को नहीं जानता, लेकिन यह बहुत संभावना है कि आपका प्रकार स्तर परn प्राकृतिक-संख्या मान का प्रतिनिधित्व करता है । यहां हम उपर्युक्त लोगों की तरह उन्नत एक्सटेंशन में गोताखोरी कर रहे हैं, प्लस DataKinds, हो सकता है GADTs, और कुछ टाइपकास्ट मशीनरी। जबकि मैं सब कुछ नहीं समझा सकता हूँ, उम्मीद है कि मैं कुछ बुनियादी जानकारी प्रदान कर सकता हूँ। intuitively,

foo :: forall n . some type using n

तर्क के रूप में @n, एक तरह का संकलन-समय प्राकृतिक है, जो रनटाइम में पारित नहीं होता है। बजाय,

foo :: forall n . C n => some type using n

लेता है @nएक साथ (संकलन समय), एक साथ सबूत है कि nसंतुष्ट रोके C n। उत्तरार्द्ध एक रन-टाइम तर्क है, जो वास्तविक मूल्य को उजागर कर सकता है n। वास्तव में, आपके मामले में, मुझे लगता है कि आपके पास बहुत कुछ जैसा है

value :: forall n . Reflects n Int => Int

जो अनिवार्य रूप से कोड को "-मान" के रूप में अनिवार्य रूप से "प्रकार" तक पहुंचने के लिए, शब्द-स्तर पर प्राकृतिक-प्रकार को लाने की अनुमति देता है। (उपरोक्त प्रकार को एक "अस्पष्ट" माना जाता है, वैसे - आपको वास्तव में आवश्यकता है@n में अवज्ञा करने की है)।

अंत में: किसी nको टाइप स्तर पर पास क्यों करना चाहिए यदि हम बाद में उसे टर्म स्तर में परिवर्तित करते हैं? केवल कार्यों को लिखना आसान नहीं होगा

foo :: Int -> ...
foo n ... = ... use n

अधिक बोझिल के बजाय

foo :: forall n . Reflects n Int => ...
foo ... = ... use (value @n)

ईमानदार जवाब है: हाँ, यह आसान होगा। हालांकि, nप्रकार के स्तर पर होने से कंपाइलर अधिक स्थिर जांच करने की अनुमति देता है। उदाहरण के लिए, आप "पूर्णांक मोडुलो n" का प्रतिनिधित्व करने के लिए एक प्रकार चाहते हैं , और उन्हें जोड़ने की अनुमति दे सकते हैं। बीत रहा है

data Mod = Mod Int  -- Int modulo some n

foo :: Int -> Mod -> Mod -> Mod
foo n (Mod x) (Mod y) = Mod ((x+y) `mod` n)

काम करता है, लेकिन कोई जाँच नहीं है xऔर yएक ही मापांक के हैं। हम सेब और संतरे जोड़ सकते हैं, अगर हम सावधान नहीं हैं। हम इसके बजाय लिख सकते हैं

data Mod n = Mod Int  -- Int modulo n

foo :: Int -> Mod n -> Mod n -> Mod n
foo n (Mod x) (Mod y) = Mod ((x+y) `mod` n)

जो बेहतर है, लेकिन foo 5 x yफिर भी जब nनहीं है तब भी कॉल करने की अनुमति देता है 5। अच्छा नही। बजाय,

data Mod n = Mod Int  -- Int modulo n

-- a lot of type machinery omitted here

foo :: forall n . SomeConstraint n => Mod n -> Mod n -> Mod n
foo (Mod x) (Mod y) = Mod ((x+y) `mod` (value @n))

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

समापन: ये बहुत ही उन्नत एक्सटेंशन हैं। यदि आप एक शुरुआत कर रहे हैं, तो आपको इन तकनीकों की दिशा में धीरे-धीरे प्रगति करने की आवश्यकता होगी। यदि आप केवल एक छोटे से अध्ययन के बाद उन्हें समझ नहीं पाते हैं, तो निराश न हों, इसमें कुछ समय लगता है। एक समय में एक छोटा सा कदम बनाएं, प्रत्येक सुविधा के बिंदु को समझने के लिए कुछ अभ्यासों को हल करें। और तुम हमेशा StackOverflow होगा जब आप फंस रहे हैं :-)


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