Tainted (empty) → 0.0.1
raw patch · 7 files changed
+278/−0 lines, 7 filesdep +basesetup-changed
Dependencies added: base
Files
- .gitignore +5/−0
- .travis.yml +0/−0
- LICENSE +28/−0
- README.md +75/−0
- Setup.hs +2/−0
- Tainted.cabal +36/−0
- src/Data/Tainted.hs +132/−0
+ .gitignore view
@@ -0,0 +1,5 @@+*.hi+*.o+*.swp+/dist+
+ .travis.yml view
+ LICENSE view
@@ -0,0 +1,28 @@+Copyright (c) 2015, Ross Meikleham+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++* Redistributions of source code must retain the above copyright notice, this+ list of conditions and the following disclaimer.++* Redistributions in binary form must reproduce the above copyright notice,+ this list of conditions and the following disclaimer in the documentation+ and/or other materials provided with the distribution.++* Neither the name of Tainted nor the names of its+ contributors may be used to endorse or promote products derived from+ this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+
+ README.md view
@@ -0,0 +1,75 @@+# Tainted+Tainted type, and associated operations ++A Tainted type contains either a clean or dirty value. Values which are+clean stay clean as long as an operation performed on them results+in a clean value. If combined with a dirty value, this taints the value+causing it to become dirty, and any further operation keeps it dirty.+This is similar to the Maybe monad except once the dirty has been+reached, calculations can still be performed on the value it contains.++One use case is evaluating whether expressions are pure from multiple+sources combining impure and pure values. This can be useful for+type checking to enforce purity in certain areas. As soon as an +impure part of an expression is reached it taints the entire+expression as impure.++A simple example given here is a expression evaluator which is given+values from different sources which are marked as pure or impure.++```Haskell+module TaintExample where++import Data.Tainted++data Expr = + Number (Tainted Int)+ | Add Expr Expr+ + deriving Show++pure1 = Number (Clean 3)+pure2 = Number (Clean 7)+impure1 = Number (Dirty 5)++expr1 = Add pure1 pure2+expr2 = Add impure1 pure1+expr3 = Add pure1 (Add impure1 pure2) ++--Evaluate expression as much as Possible+evalExpr :: Expr -> Expr+evalExpr (Number n) = Number n+evalExpr (Add e1 e2) = + case (evalExpr e1, evalExpr e2) of+ (Number i, Number j) -> Number $ (+) <$> i <*> j+ (x, y) -> Add x y++reducedExpr1 = evalExpr expr1+reducedExpr2 = evalExpr expr2+reducedExpr3 = evalExpr expr3+```++Evaluating expr1:+```Haskell+Number (Clean 10)+```+Adding 2 clean values 7 and 3 gives a clean value, clean+values haven't become tainted++Evaluating expr2:+```Haskell+Number (Dirty 8)+```+Adding a clean value 3 and dirty value 5 taints the expression as dirty+so the expression evaluates to dirty value of 8+++Evaluating expr3:+```Haskell+Number (Dirty 15)+```+This shows the propogation of dirty states, as the inner expression+evaluates to a dirty value, then added with a clean value still+gives a dirty value.++
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ Tainted.cabal view
@@ -0,0 +1,36 @@+-- Initial Tainted.cabal generated by cabal init. For further +-- documentation, see http://haskell.org/cabal/users-guide/++name: Tainted+version: 0.0.1+synopsis: Tainted type, and associated operations+description: Tainted type, and associated operations+homepage: https://github.com/RossMeikleham/Tainted+license: BSD3+license-file: LICENSE+author: RossMeikleham+maintainer: rossmeikleham@hotmail.co.uk+copyright: Copyright (C) 2015 Ross Meikleham+category: Data, Monads+build-type: Simple+cabal-version: >=1.10+extra-source-files:+ .gitignore+ .travis.yml+ README.md+++source-repository head + type: git+ location: git://github.com/RossMeikleham/Tainted.git+++library+ exposed-modules: Data.Tainted+ build-depends: base >=4.8 && <4.9+ hs-source-dirs: src+ default-language: Haskell2010+ ghc-options: -Wall+ + +
+ src/Data/Tainted.hs view
@@ -0,0 +1,132 @@+-----------------------------------------------------------------------------+-- |+-- Module : Control.Monad+-- Copyright : Ross Meikleham+-- License : BSD-style +-- +-- Maintainer : RossMeikleham@hotmail.co.uk+-- Stability : provisional+-- Portability : portable+--+-- The Tainted type, and associated operations.+-----------------------------------------------------------------------------++module Data.Tainted + (Tainted(..), isClean, isDirty, cleans, dirtys, partitionTaints)++where++import Control.Monad+import Data.Typeable+++-- | The 'Tainted' type encapsulates a value. A value of type+-- @'Tainted' a@ either contains a "clean" value of type @a@ (represented as @'Clean' a@), +-- or it contains a "dirty" value of type @a@ (represented as @'Dirty' a@). +--+-- The 'Tainted' type is also a monad. Once the "dirty" state has been+-- reached, and clean operations performed themselves create a "dirty"+-- value. +data Tainted a = Dirty a | Clean a+ deriving (Eq, Ord, Read, Show, Typeable)++-- Identity law:+--+-- fmap id (Dirty a) = Dirty (id a) = Dirty a => fmap id = id +-- +-- Same proof can be generalized for Clean+--+-- Composition law:+--+-- ((fmap p) . (fmap q)) (Dirty a) = fmap p (Dirty (q a) = (Dirty ((p . q) a)) +-- = fmap (p . q)+--+-- Same proof can be generalized for Clean+instance Functor Tainted where+ fmap f (Dirty a) = Dirty (f a)+ fmap f (Clean a) = Clean (f a)+++-- Proof of correctness comes from Monad correctness+instance Applicative Tainted where+ pure = return+ (<*>) = ap+ +-- Left Identity Law:+--+-- (return x) >>= f = Clean f x ≡ f x+--+-- Right Identity Law:+--+-- m >>= return ≡ m +--+-- proof is in definition of the Clean case below for (>>=)+--+-- Associativity Law:+--+-- Case of m being Clean :+-- +-- LHS: (Clean a >>= f) >>= g = f a >>= g +-- RHS: Clean a >>= (\x -> f x >>= g) = f a >>= g+-- LHS = RHS+--+-- Case of m being Dirty:+--+-- LHS: (Dirty a >>= f) >>= g = +-- g =<< case f a of +-- (Clean y) -> Dirty y+-- y -> y+--+-- RHS: Dirty a >>= (\x -> f x >>= g) = +-- g =<< case f a of+-- (Clean y) -> Dirty y+-- y -> y +-- LHS = RHS+instance Monad Tainted where+ return = Clean+ Dirty x >>= f = case f x of+ (Clean y) -> Dirty y+ y -> y + Clean x >>= f = f x+++-- ---------------------------------------------------------------------------+-- The Tainted type, and instances+++-- | Returns 'True' iff its argument is of the form 'Clean _.+isClean :: Tainted a -> Bool+isClean (Clean _) = True+isClean _ = False+++-- | Returns 'True' iff its argument is of the form Dirty _. +isDirty :: Tainted a -> Bool +isDirty = not . isClean +++-- | Extracts from a list of 'Tainted' all the 'Clean' elements. +-- All the 'Clean' elements are extracted in order.+cleans :: [Tainted a] -> [a]+cleans = map extractTaint . filter isClean +++-- | Extracts from a list of 'Tainted' all the 'Dirty' elements.+-- All the 'Dirty' elements are extracted in order.+dirtys :: [Tainted a] -> [a]+dirtys = map extractTaint . filter isDirty+++-- | Partitions a list of 'Tainted' into two lists. +-- All the 'Dirty' elements are extracted, in order, to the first component of the output. +-- Similarly the 'Clean' elements are extracted to the second component of the output.+partitionTaints :: [Tainted a] -> ([a], [a])+partitionTaints ts = (c, d)+ where c = cleans ts+ d = dirtys ts+++-- | Extract the value contained in a 'Tainted' type+extractTaint :: Tainted a -> a+extractTaint (Clean a) = a+extractTaint (Dirty a) = a