Policy
'un yapıcılarına erişimi olan herkes, Policy
numaralı parçayı ayrı bir yere alabilir ve muhtemelen bir araya getirerek bir araya getirebilir. Bu modülün dışındaki Policy
yapıcısını gösterme. Bunun yerine, iyi biçimlendirilmiş olması garantili ve Monoid
arabirimini invaryanları kırmadan bunları oluşturmak için ortaya çıkan ilkeleri oluşturmak için smart constructor sağlayın. Policy
tip özetinin tutulması, parasal olmayan politikalarla sonuçlanabilecek tüm kodların bu modülde tutulmasını sağlar. bir Monoid
örneğine bir Ord
örneği döner the monoid for functions, fonksiyon tuşu aracılığıyla nokta-bazlı bir Monoid kaldırır ve the Max
newtype:
{-# 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)
I base
den Monoid
örnekleri bir çift ödünç GeneralizedNewtypeDeriving
kullanıyorum Aşağıda her zaman mappend
'un argümanlarını daha büyük seçerek. politikaları oluştururken
Yani Policy
bireyin Monoid
örneği otomatik Level
sıralamasını yönetecek: Belirli bir role çelişen seviyeleri ile iki politikaları oluştururken her zaman daha hoşgörülü birini seçeceğim. Bu,'u ek işlemini yapar: ilkeleri, hiç kimseye izin vermeyen "varsayılan" ilke olan mempty
'a ekleyerek tanımlayabilirsiniz.
newtype Policy = Policy (Role -> Max Level) deriving (Semigroup, Monoid)
grant
Role
ve Level
sıralamasının özelliklerini saygı ilkeleri üreten bir akıllı yapıcı olup. Bir role izin vermenin de daha fazla ayrıcalıklı rollere izin verdiğinden emin olmak için >=
ile rolleri karşılaştırdığımı unutmayın.
grant :: Role -> Level -> Policy
grant r l = Policy (Max . pol)
where pol r'
| r' >= r = l
| otherwise = None
can
bir politika verilen bir role verilen bir erişim seviyesi verir olmadığını belirten bir gözlem olduğunu.Bir kez daha fazla izin veren düzeylerin daha az izin verici olanları içerdiğinden emin olmak için >=
kullanıyorum.
can :: Role -> Level -> Policy -> Bool
(r `can` l) (Policy f) = getMax (f r) >= l
Bu modülün ne kadar küçük bir kod aldığına hoş bir şekilde şaşırdım! deriving
mekanizmasına, özellikle de GeneralizedNewtypeDeriving
mekanizmasına yaslanmak, "sıkıcı" kodun sorumlularını koymak için gerçekten güzel bir yöntemdir, böylece önemli şeylere odaklanabilirsiniz. Bu politikaların
Kullanımı şuna benzer:
module Client where
import Data.Monoid ((<>))
import Policy
Basit olanlar dışında karmaşık politikaları oluşturmak için Monoid
sınıfını kullanabilirsiniz.
ownerEdit, contributorView, myPolicy :: Policy
ownerEdit = grant Owner Edit
contributorView = grant Contributor View
myPolicy = ownerEdit <> contributorView
Ve politikaları test etmek can
işlevini kullanabilirsiniz. Örneğin
canPublicView :: Policy -> Bool
canPublicView = Public `can` View
:
ghci> canPublicView myPolicy
False
Max a' bir Monoid ve olduğu 'Çünkü GHC Policy'' için Monoid örneğini türetmek yapabiliyor doğru olduğunu Am I 'x -> Monoid y' Monoid'dir. Kendi örneğimi de alabilirim: '' (Politika a) 'mappend' (Politika b) = Politika $ \ r -> max (ar) (br)' '' – homam
Evet, GHC tam olarak aynı şekilde üretecektir kod, bu yüzden neden yazmayı bother? –
Bu çok zarif bir çözümdür. Teşekkürler! – homam