Policy
के कन्स्ट्रक्टर तक पहुंच वाले किसी भी व्यक्ति को Policy
अलग-अलग ले जाया जा सकता है और संभवतः एक गैरकानूनी फैशन में इसे एक साथ रख सकता है। इस मॉड्यूल के बाहर Policy
कन्स्ट्रक्टर का पर्दाफाश न करें। इसके बजाय, उन नीतियों को बनाने के लिए smart constructor प्रदान करें जो अच्छी तरह से गठित होने की गारंटी है और Monoid
इंटरफ़ेस का खुलासा किए बिना उन्हें लिखने के लिए खुलासा करें। Policy
टाइप अमूर्त को बनाए रखने से यह सुनिश्चित होता है कि इस कोड के अंदर गैरकानूनी नीतियों के परिणामस्वरूप सभी कोड रखा जा सके।
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Policy (
Role(..),
Level(..),
Policy, -- keep Policy abstract by not exposing the constructor
can
) where
import Data.Semigroup (Semigroup, Max(..))
data Role = Public | Contributor | Owner
deriving (Eq, Ord, Bounded, Enum, Show, Read)
data Level = None | View | Edit
deriving (Eq, Ord, Bounded, Enum, Show, Read)
नीचे मैं base
से Monoid
उदाहरणों की एक जोड़ी उधार लेने के लिए GeneralizedNewtypeDeriving
उपयोग कर रहा हूँ: the monoid for functions, जो समारोह तीर के माध्यम से बिंदु के लिहाज से एक और monoid लिफ्टों, और the Max
newtype, जिसके द्वारा एक Monoid
उदाहरण में एक Ord
उदाहरण बदल जाता है हमेशा mappend
के तर्कों का बड़ा चयन करें।
तो Policy
के Monoid
उदाहरण स्वचालित रूप से होने वाली नीतियों की रचना Level
के आदेश का प्रबंधन करेगा: जब किसी दिए गए भूमिका पर परस्पर विरोधी के स्तर के साथ दो नीतियों रचना हम हमेशा अधिक अनुमोदक एक का चयन करेंगे। यह <>
योजक ऑपरेशन बनाता है: आप "डिफ़ॉल्ट" नीति, mempty
पर अनुमतियां जोड़कर नीतियों को परिभाषित करते हैं, जो कि किसी को भी अनुमति नहीं देता है।
newtype Policy = Policy (Role -> Max Level) deriving (Semigroup, Monoid)
grant
एक स्मार्ट निर्माता जो नीतियों Role
और Level
के आदेश गुण का सम्मान पैदा करता है। ध्यान दें कि मैं भूमिका निभाने की अनुमति देने के लिए >=
के साथ भूमिकाओं की तुलना कर रहा हूं ताकि अधिक विशेषाधिकार प्राप्त भूमिकाओं की अनुमति भी मिल सके।
grant :: Role -> Level -> Policy
grant r l = Policy (Max . pol)
where pol r'
| r' >= r = l
| otherwise = None
can
एक अवलोकन जिससे आपको पता चलता एक नीति किसी दिए गए भूमिका के लिए किसी दिए गए पहुँच स्तर अनुदान या नहीं।एक बार मैं >=
का उपयोग कर यह सुनिश्चित करने के लिए उपयोग कर रहा हूं कि अधिक अनुमोदित स्तर कम अनुमोदित लोगों को इंगित करें।
can :: Role -> Level -> Policy -> Bool
(r `can` l) (Policy f) = getMax (f r) >= l
मुझे आश्चर्य हुआ कि इस मॉड्यूल ने कितना छोटा कोड लिया था! deriving
तंत्र पर विशेष रूप से GeneralizedNewtypeDeriving
पर झुकाव, प्रकारों को "उबाऊ" कोड के प्रभारी रखने का एक बहुत अच्छा तरीका है ताकि आप महत्वपूर्ण सामग्री पर ध्यान केंद्रित कर सकें।
इन नीतियों का उपयोग इस तरह दिखता है:
module Client where
import Data.Monoid ((<>))
import Policy
आप सरल लोगों से बाहर जटिल नीतियों का निर्माण करने के Monoid
वर्ग का उपयोग कर सकते हैं।
ownerEdit, contributorView, myPolicy :: Policy
ownerEdit = grant Owner Edit
contributorView = grant Contributor View
myPolicy = ownerEdit <> contributorView
और आप नीतियों का परीक्षण करने के लिए can
फ़ंक्शन का उपयोग कर सकते हैं।
canPublicView :: Policy -> Bool
canPublicView = Public `can` View
उदाहरण के लिए:
ghci> canPublicView myPolicy
False
I Am क्योंकि 'मैक्स A' एक monoid और सही है कि GHC' Policy' के लिए एक monoid उदाहरण प्राप्त करने में सक्षम है 'एक्स -> monoid y' एक मोनॉयड है। मैं अपना खुद का 'उदाहरण भी प्राप्त कर सकता हूं: '' '(पॉलिसी ए)' मैपेंड '(पॉलिसी बी) = पॉलिसी $ \ r -> अधिकतम (एआर) (बीआर)' ' – homam
हां, हालांकि जीएचसी बिल्कुल वही उत्पन्न करेगा कोड, तो इसे लिखने से परेशान क्यों? –
यह एक बहुत ही सुरुचिपूर्ण समाधान है। धन्यवाद! – homam