Aleksey Khudyakov avatar Aleksey Khudyakov committed 8c1425f

Compare for equality

Comments (0)

Files changed (1)

Test/QuickCheck/Property/Utils.hs

+{-# LANGUAGE TypeFamilies     #-}
+{-# LANGUAGE FlexibleContexts #-}
+-- | 
+-- A lot of QuickCheck properties have form @expression = another
+-- expression@. It's natural to compare them for equality however not
+-- all types have 'Eq' instance. For example functions and hence many
+-- monads.
+--
+-- There are three generic ways to compare values for equality.
+--
+--  (1) Use '==' operator
+--
+--  2. Convert value to some type with Eq instance and compare
+--     them. Caller must ensure that such conversion make sence
+--
+--  3. Most generic: use custom comparison function.
+--
+-- Functions 'eq', 'eqOn' and 'eqWith' provide this functionality.
+module Test.QuickCheck.Property.Utils (
+    -- * Comparison for equality
+    Equal(..)
+  , Equalable(..)
+  , eq
+  , eqOn
+  , eqWith
+    -- * Utils
+  , T(..)
+    -- * Examples
+  ) where
+
+import Data.Function (on)
+
+
+-- | Values to be compared for equality
+data Equal a = Equal a a
+
+-- | Recurse through function to apply comparison to 'Equal'.
+class Equalable a where
+  -- | Type which should be compared for equality
+  type Result a :: *
+  -- | Result of comparison
+  type Compared a :: *
+  -- | Compare 
+  equalWith :: (Result a -> Result a -> Bool) -> a -> Compared a
+                
+instance Equalable (Equal a) where
+  type Result   (Equal a) = a
+  type Compared (Equal a) = Bool
+  equalWith f (Equal a b) = f a b
+
+instance Equalable a => Equalable (x -> a) where
+  type Result   (x -> a) = Result a
+  type Compared (x -> a) = x -> Compared a
+  equalWith f fun = equalWith f . fun
+
+
+-- | Compare values using @==@ 
+eq :: (Equalable a, Eq (Result a)) => a -> Compared a
+eq = equalWith (==)
+
+-- | Convert values to types which could be compare
+eqOn :: (Equalable a, Eq b) => (Result a -> b) -> a -> Compared a
+eqOn f = equalWith ((==) `on` f)
+
+-- | Compare with custom function. Just a shorter sinonym for equalWith
+eqWith :: (Equalable a) => (Result a -> Result a -> Bool) -> a -> Compared a
+eqWith = equalWith
+
+
+-- | Data type is used to fix concrete data in properties
+data T a = T
+
+-- $examples
+-- None so far
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.