AC-MiniTest-1.1.1: Test/AC/Label.hs
{- |
Defines the 'Label' type, for making values 'show'able.
-}
{-# LANGUAGE FlexibleContexts #-}
module Test.AC.Label where
---------------------------------------------------------------------
{- |
The @Label@ type.
A value of type @Label x@ is really a value of type @x@, but with
a textual label. The 'Show' instance returns this label.
This can be tremendously useful for allowing you to 'show' values
which would not otherwise be printable. For example, functions.
Rather than passing a function, you can pass a labelled function.
This allows you to know, at runtime, /which/ function you're
dealing with, which is very useful for test purposes.
You can use 'label' to extract the label text, and 'value' to
extract the actual data value.
The 'Show' instance uses the 'label', but the other instances use
only the 'value', ignoring the 'label'. (In particular, any
operations which alter the 'value' leave the 'label' untouched.)
-}
data Label x = Label {label :: String, value :: !x}
instance Eq x => Eq (Label x) where
x == y = (value x) == (value y)
instance Ord x => Ord (Label x) where
compare x y = compare (value x) (value y)
instance Enum x => Enum (Label x) where
succ x = x {value = succ (value x)}
pred x = x {value = pred (value x)}
toEnum i = Label {label = "toEnum", value = toEnum i}
fromEnum = fromEnum . value
enumFrom x = map (Label (label x)) (enumFrom (value x) )
enumFromThen x y = map (Label (label x)) (enumFromThen (value x) (value y) )
enumFromTo x y = map (Label (label x)) (enumFromTo (value x) (value y) )
enumFromThenTo x y z = map (Label (label x)) (enumFromThenTo (value x) (value y) (value z))
instance Bounded x => Bounded (Label x) where
minBound = Label "minBound" minBound
maxBound = Label "maxBound" maxBound
instance Show (Label x) where show = label
---------------------------------------------------------------------
{- |
This type is similar to 'Label'. However, 'Label' cannot be made
an instance of higher-kinded classes such as 'Functor' and 'Monad'.
This type gets around that irritating limitation.
-}
data Label1 c x1 = Label1 {label1 :: String, value1 :: c x1}
instance Eq (c x1) => Eq (Label1 c x1) where
x == y = (value1 x) == (value1 y)
instance Ord (c x1) => Ord (Label1 c x1) where
compare x y = compare (value1 x) (value1 y)
instance Enum (c x1) => Enum (Label1 c x1) where
succ x = x {value1 = succ (value1 x)}
pred x = x {value1 = pred (value1 x)}
toEnum i = Label1 {label1 = "toEnum", value1 = toEnum i}
fromEnum = fromEnum . value1
enumFrom x = map (Label1 (label1 x)) (enumFrom (value1 x) )
enumFromThen x y = map (Label1 (label1 x)) (enumFromThen (value1 x) (value1 y) )
enumFromTo x y = map (Label1 (label1 x)) (enumFromTo (value1 x) (value1 y) )
enumFromThenTo x y z = map (Label1 (label1 x)) (enumFromThenTo (value1 x) (value1 y) (value1 z))
instance Bounded (c x1) => Bounded (Label1 c x1) where
minBound = Label1 "minBound" minBound
maxBound = Label1 "maxBound" maxBound
instance Show (Label1 c x1) where show = label1
instance Functor c => Functor (Label1 c) where
fmap f l = l {value1 = fmap f (value1 l)}
instance Monad c => Monad (Label1 c) where
return x = Label1 {label1 = "return", value1 = return x}
lc >>= f = lc {value1 = value1 lc >>= \ x -> let lc' = f x in value1 lc'}