packages feed

Tainted (empty) → 0.0.1

raw patch · 7 files changed

+278/−0 lines, 7 filesdep +basesetup-changed

Dependencies added: base

Files

+ .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