diff --git a/src/Data/Validity.hs b/src/Data/Validity.hs
--- a/src/Data/Validity.hs
+++ b/src/Data/Validity.hs
@@ -29,7 +29,6 @@
 
     > instance Validity Prime where
     >     validate (Prime n) = isPrime n <?@> "The 'Int' is prime."
-    >     isValid (Prime n) = isPrime n
 
     If certain typeclass invariants exist, you can make these explicit in the
     validity instance as well.
@@ -38,18 +37,15 @@
     -}
 module Data.Validity
     ( Validity(..)
-    -- * Helper functions to define 'isValid'
-    , triviallyValid
+    , isValid
     -- * Helper functions to define 'validate'
     , trivialValidation
-    , isValidByValidating
     , check
-    , (<?!>)
+    , declare
     , annotate
-    , (<?@>)
-    , validateByChecking
-    , validateByCheckingName
-    , validateByCheckingDefault
+    , delve
+    , invalid
+    , valid
     -- * Utilities
     -- ** Utilities for validity checking
     , isInvalid
@@ -62,6 +58,9 @@
     , prettyValidation
     -- * Re-exports
     , Monoid(..)
+#if MIN_VERSION_base(4,11,0)
+    , Semigroup(..)
+#endif
     ) where
 
 import Data.Either (isRight)
@@ -76,6 +75,7 @@
 import Data.Monoid
 import Data.Ratio
 #endif
+import Data.Int (Int, Int16, Int32, Int64, Int8)
 import Data.Word (Word, Word16, Word32, Word64, Word8)
 import GHC.Generics
 #if MIN_VERSION_base(4,8,0)
@@ -92,14 +92,14 @@
 -- reasons why the given value is not valid if that is the case.
 --
 -- 'isValid' only checks whether a given value is a valid value of its type.
+-- It is a helper function that checks that 'validate' says that there are
+-- no reasons why the value is invalid.
 --
 -- === Instantiating 'Validity'
 --
--- To instantiate 'Validity', one has to implement both 'isValid' and
--- 'validate'.
--- Start by implementing 'validate'. Use the helper functions below to define
--- all the reasons why a given value would be a valid value of its type.
--- Then define `isValid = isValidbyValidating' for now.
+-- To instantiate 'Validity', one has to implement only 'validate'.
+-- Use the helper functions below to define all the reasons why a given
+-- value would be a valid value of its type.
 --
 -- Example:
 --
@@ -108,22 +108,7 @@
 -- > instance Validity Even
 -- >     validate (Event i)
 -- >       even i <?@> "The contained 'Int' is even."
--- >     isValid = isValidByValidating
 --
--- If it turns out that, at this point, 'isValid' is too slow for your taste,
--- you can replace the implementation of 'isValid' by a custom implementation.
--- However, it is important that this 'isValid' implementation has exactly
--- the same semantics as 'isValidbyValidating'.
---
--- Example:
---
--- > newtype Even = Even Int
--- >
--- > instance Validity Even
--- >     validate (Event i)
--- >       even i <?@> "The contained 'Int' is even."
--- >     isValid (Event i) = even i
---
 -- === Semantics
 --
 -- 'isValid' should be an underapproximation of actual validity.
@@ -150,7 +135,7 @@
 -- === Automatic instances with 'Generic'
 --
 -- An instance of this class can be made automatically if the type in question
--- has a 'Generic' instance. This instance will try to use 'isValid' to
+-- has a 'Generic' instance. This instance will try to use 'valid' to
 -- on all structural sub-parts of the value that is being checked for validity.
 --
 -- Example:
@@ -167,8 +152,6 @@
 -- generates something like:
 --
 -- > instance Validity MyType where
--- >     isValid (MyType d s)
--- >         = isValid d && isValid s
 -- >     validate (MyType d s)
 -- >         = d <?!> "myDouble"
 -- >        <> s <?!> "myString"
@@ -177,10 +160,10 @@
     default validate :: (Generic a, GValidity (Rep a)) =>
         a -> Validation
     validate = gValidate . from
-    isValid :: a -> Bool
-    default isValid :: a -> Bool
-    isValid = isRight . checkValidity
 
+isValid :: Validity a => a -> Bool
+isValid = isRight . checkValidity
+
 data ValidationChain
     = Violated String
     | Location String
@@ -194,48 +177,23 @@
     } deriving (Show, Eq, Generic)
 
 instance Validity Validation
-
+#if MIN_VERSION_base(4,11,0)
+instance Semigroup Validation where
+    (Validation v1) <> (Validation v2) = Validation $ v1 ++ v2
+#endif
 instance Monoid Validation where
     mempty = Validation []
+#if MIN_VERSION_base(4,11,0)
+    mappend = (<>)
+#else
     mappend (Validation v1) (Validation v2) = Validation $ v1 ++ v2
-
--- | Declare any value to be valid.
---
--- > triviallyValid a = seq a True
-triviallyValid :: a -> Bool
-triviallyValid a = seq a True
-
--- | Implement 'isValid' by using 'validate' and checking that there are no
--- reasons that the value is invalid.
-isValidByValidating :: Validity a => a -> Bool
-isValidByValidating = isRight . checkValidity
-
+#endif
 -- | Declare any value to be valid in validation
 --
 -- > trivialValidation a = seq a mempty
 trivialValidation :: a -> Validation
 trivialValidation a = seq a mempty
 
--- | Implement 'validate' by using 'isValid' and using the given string as the
--- reason if the value is invalid.
-validateByChecking :: Validity a => String -> a -> Validation
-validateByChecking s a = isValid a <?@> s
-
--- | Implement 'validate' by using 'isValid' and using the given name to define
--- the reason if the value is invalid.
---
--- > validateByCheckingName name = validateByChecking $ unwords ["The", name, "valid."]
-validateByCheckingName :: Validity a => String -> a -> Validation
-validateByCheckingName name =
-    validateByChecking $ unwords ["The", name, "valid."]
-
--- | Implement 'validate' by using 'isValid' and using a default reason if the
--- value is invalid.
---
--- > validateByCheckingDefault = validateByChecking "The value is valid."
-validateByCheckingDefault :: Validity a => a -> Validation
-validateByCheckingDefault = validateByChecking "The value is valid."
-
 -- | Check that a given invariant holds.
 --
 -- The given string should describe the invariant, not the violation.
@@ -253,15 +211,29 @@
         then mempty
         else Validation [Violated err]
 
--- | Infix operator for 'check'
+-- | 'check', but with the arguments flipped
+declare :: String -> Bool -> Validation
+declare = flip check
+
+-- | Construct a trivially invalid 'Validation'
 --
 -- Example:
 --
--- > x < 5 <?@> "x is strictly smaller than 5"
-(<?@>) :: Bool -> String -> Validation
-(<?@>) = check
+-- > data Wrong
+-- >     = Wrong
+-- >     | Fine
+-- >     deriving (Show, Eq)
+-- >
+-- > instance Validity Wrong where
+-- >     validate w =
+-- >         case w of
+-- >             Wrong -> invalid "Wrong"
+-- >             Fine -> valid
+invalid :: String -> Validation
+invalid = check False
 
-infixr 0 <?@>
+valid :: Validation
+valid = mempty
 
 -- | Declare a sub-part as a necessary part for validation, and annotate it with a name.
 --
@@ -275,70 +247,53 @@
 annotate :: Validity a => a -> String -> Validation
 annotate = annotateValidation . validate
 
--- | Infix operator for 'annotate'
---
--- Example:
---
--- > validate (a, b) =
--- >     mconcat
--- >         [ a <?!> "The first element of the tuple"
--- >         , b <?!> "The second element of the tuple"
--- >         ]
-(<?!>) :: Validity a => a -> String -> Validation
-(<?!>) = annotate
-
-infixr 0 <?!>
+-- | 'annotate', but with the arguments flipped.
+delve :: Validity a => String -> a -> Validation
+delve = flip annotate
 
 -- | Any tuple of things is valid if both of its elements are valid
 instance (Validity a, Validity b) => Validity (a, b) where
-    isValid (a, b) = isValid a && isValid b
     validate (a, b) =
         mconcat
-            [ a <?!> "The first element of the tuple"
-            , b <?!> "The second element of the tuple"
+            [ annotate a "The first element of the tuple"
+            , annotate b "The second element of the tuple"
             ]
 
 -- | Any Either of things is valid if the contents are valid in either of the cases.
 instance (Validity a, Validity b) => Validity (Either a b) where
-    isValid (Left a) = isValid a
-    isValid (Right b) = isValid b
-    validate (Left a) = a <?!> "The 'Left'"
-    validate (Right b) = b <?!> "The 'Right'"
+    validate (Left a) = annotate a "The 'Left'"
+    validate (Right b) = annotate b "The 'Right'"
 
 -- | Any triple of things is valid if all three of its elements are valid
 instance (Validity a, Validity b, Validity c) => Validity (a, b, c) where
-    isValid (a, b, c) = isValid a && isValid b && isValid c
     validate (a, b, c) =
         mconcat
-            [ a <?!> "The first element of the triple"
-            , b <?!> "The second element of the triple"
-            , c <?!> "The third element of the triple"
+            [ annotate a "The first element of the triple"
+            , annotate b "The second element of the triple"
+            , annotate c "The third element of the triple"
             ]
 
 -- | Any quadruple of things is valid if all four of its elements are valid
 instance (Validity a, Validity b, Validity c, Validity d) =>
          Validity (a, b, c, d) where
-    isValid (a, b, c, d) = isValid a && isValid b && isValid c && isValid d
     validate (a, b, c, d) =
         mconcat
-            [ a <?!> "The first element of the quadruple"
-            , b <?!> "The second element of the quadruple"
-            , c <?!> "The third element of the quadruple"
-            , d <?!> "The fourth element of the quadruple"
+            [ annotate a "The first element of the quadruple"
+            , annotate b "The second element of the quadruple"
+            , annotate c "The third element of the quadruple"
+            , annotate d "The fourth element of the quadruple"
             ]
 
 -- | Any quintuple of things is valid if all five of its elements are valid
 instance (Validity a, Validity b, Validity c, Validity d, Validity e) =>
          Validity (a, b, c, d, e) where
-    isValid (a, b, c, d, e) =
-        isValid a && isValid b && isValid c && isValid d && isValid e
     validate (a, b, c, d, e) =
         mconcat
-            [ a <?!> "The first element of the quintuple"
-            , b <?!> "The second element of the quintuple"
-            , c <?!> "The third element of the quintuple"
-            , d <?!> "The fourth element of the quintuple"
-            , e <?!> "The fifth element of the quintuple"
+            [ annotate a "The first element of the quintuple"
+            , annotate b "The second element of the quintuple"
+            , annotate c "The third element of the quintuple"
+            , annotate d "The fourth element of the quintuple"
+            , annotate e "The fifth element of the quintuple"
             ]
 
 -- | Any sextuple of things is valid if all six of its elements are valid
@@ -350,17 +305,14 @@
          , Validity f
          ) =>
          Validity (a, b, c, d, e, f) where
-    isValid (a, b, c, d, e, f) =
-        isValid a &&
-        isValid b && isValid c && isValid d && isValid e && isValid f
     validate (a, b, c, d, e, f) =
         mconcat
-            [ a <?!> "The first element of the sextuple"
-            , b <?!> "The second element of the sextuple"
-            , c <?!> "The third element of the sextuple"
-            , d <?!> "The fourth element of the sextuple"
-            , e <?!> "The fifth element of the sextuple"
-            , f <?!> "The sixth element of the sextuple"
+            [ annotate a "The first element of the sextuple"
+            , annotate b "The second element of the sextuple"
+            , annotate c "The third element of the sextuple"
+            , annotate d "The fourth element of the sextuple"
+            , annotate e "The fifth element of the sextuple"
+            , annotate f "The sixth element of the sextuple"
             ]
 
 -- | A list of things is valid if all of the things are valid.
@@ -369,12 +321,11 @@
 -- If the empty list should not be considered valid as part of your custom data
 -- type, make sure to write a custom @Validity instance@
 instance Validity a => Validity [a] where
-    isValid = all isValid
     validate =
         mconcat .
         map
             (\(ix, e) ->
-                 e <?!>
+                 annotate e $
                  unwords
                      [ "The element at index"
                      , show (ix :: Integer)
@@ -386,11 +337,10 @@
 --
 -- See the instance for 'Validity [a]' for more information.
 instance Validity a => Validity (NonEmpty a) where
-    isValid = all isValid
     validate (e :| es) =
         mconcat
-            [ e <?!> "The first element of the nonempty list"
-            , es <?!> "The rest of the elements of the nonempty list"
+            [ annotate e "The first element of the nonempty list"
+            , annotate es "The rest of the elements of the nonempty list"
             ]
 #endif
 -- | A Maybe thing is valid if the thing inside is valid or it's nothing
@@ -398,71 +348,74 @@
 -- If Nothing wasn't valid, you wouldn't have used a Maybe
 -- in the datastructure.
 instance Validity a => Validity (Maybe a) where
-    isValid Nothing = True
-    isValid (Just a) = isValid a
     validate Nothing = mempty
-    validate (Just a) = a <?!> "The 'Just'"
+    validate (Just a) = annotate a "The 'Just'"
 
 -- | Trivially valid
 instance Validity () where
-    isValid = triviallyValid
-    validate = validateByCheckingName "()"
+    validate = trivialValidation
 
 -- | Trivially valid
 instance Validity Bool where
-    isValid = triviallyValid
-    validate = validateByCheckingName "Bool"
+    validate = trivialValidation
 
 -- | Trivially valid
 instance Validity Ordering where
-    isValid = triviallyValid
-    validate = validateByCheckingName "Ordering"
+    validate = trivialValidation
 
 -- | Trivially valid
 instance Validity Char where
-    isValid = triviallyValid
-    validate = validateByCheckingName "Char"
+    validate = trivialValidation
 
 -- | Trivially valid
 instance Validity Int where
-    isValid = triviallyValid
-    validate = validateByCheckingName "Int"
+    validate = trivialValidation
 
 -- | Trivially valid
+instance Validity Int8 where
+    validate = trivialValidation
+
+-- | Trivially valid
+instance Validity Int16 where
+    validate = trivialValidation
+
+-- | Trivially valid
+instance Validity Int32 where
+    validate = trivialValidation
+
+-- | Trivially valid
+instance Validity Int64 where
+    validate = trivialValidation
+
+-- | Trivially valid
 instance Validity Word where
-    isValid = triviallyValid
-    validate = validateByCheckingName "Word"
+    validate = trivialValidation
 
 -- | Trivially valid
 instance Validity Word8 where
-    isValid = triviallyValid
-    validate = validateByCheckingName "Word8"
+    validate = trivialValidation
 
 -- | Trivially valid
 instance Validity Word16 where
-    isValid = triviallyValid
-    validate = validateByCheckingName "Word16"
+    validate = trivialValidation
 
 -- | Trivially valid
 instance Validity Word32 where
-    isValid = triviallyValid
-    validate = validateByCheckingName "Word34"
+    validate = trivialValidation
 
 -- | Trivially valid
 instance Validity Word64 where
-    isValid = triviallyValid
-    validate = validateByCheckingName "Word64"
+    validate = trivialValidation
 
 -- | NOT trivially valid:
 --
 -- * NaN is not valid.
 -- * Infinite values are not valid.
 instance Validity Float where
-    isValid f = not (isNaN f) && not (isInfinite f)
     validate f =
         mconcat
-            [ not (isNaN f) <?@> "The Float is not Nan."
-            , not (isInfinite f) <?@> "The Float is not infinite."
+            [ declare "The Float is not Nan." $ not (isNaN f)
+            , declare "The Float is not infinite." $ not (isInfinite f)
             ]
 
 -- | NOT trivially valid:
@@ -470,11 +423,10 @@
 -- * NaN is not valid.
 -- * Infinite values are not valid.
 instance Validity Double where
-    isValid d = not (isNaN d) && not (isInfinite d)
     validate d =
         mconcat
-            [ not (isNaN d) <?@> "The Double is not NaN."
-            , not (isInfinite d) <?@> "The Double is not infinite."
+            [ declare "The Double is not NaN." $ not (isNaN d)
+            , declare "The Double is not infinite." $ not (isInfinite d)
             ]
 
 -- | Trivially valid
@@ -486,30 +438,26 @@
 -- assuming that an 'Integer' is always valid.
 -- Even though this is not technically sound, it is good enough for now.
 instance Validity Integer where
-    isValid = triviallyValid
-    validate = validateByCheckingName "Integer"
+    validate = trivialValidation
 #if MIN_VERSION_base(4,8,0)
 -- | Valid according to 'isValidNatural'
 --
 -- Only available with @base >= 4.8@.
 instance Validity Natural where
-    isValid = isValidNatural
-    validate = validateByChecking "Natural"
+    validate n = check (isValidNatural n) "The Natural is valid."
 #endif
 -- | Valid if the contained numbers are valid and the denominator is
 -- strictly positive.
 instance (Num a, Ord a, Validity a) => Validity (Ratio a) where
-    isValid (n :% d) = isValid n && isValid d && d > 0
     validate (n :% d) =
         mconcat
-            [ n <?!> "The numerator"
-            , d <?!> "The denominator"
-            , (d > 0) <?@> "The denominator is strictly positive."
+            [ annotate n "The numerator"
+            , annotate d "The denominator"
+            , declare "The denominator is strictly positive." $ d > 0
             ]
 
 -- | Valid according to the contained 'Integer'.
 instance HasResolution a => Validity (Fixed a) where
-    isValid (MkFixed i) = isValid i
     validate (MkFixed i) = validate i
 
 annotateValidation :: Validation -> String -> Validation
@@ -518,41 +466,31 @@
         Validation errs -> Validation $ map (Location s) errs
 
 class GValidity f where
-    gIsValid :: f a -> Bool
     gValidate :: f a -> Validation
 
 instance GValidity U1 where
-    gIsValid = triviallyValid
     gValidate = trivialValidation
 
 instance GValidity V1 where
-    gIsValid = triviallyValid
     gValidate = trivialValidation
 
 instance (GValidity a, GValidity b) => GValidity (a :*: b) where
-    gIsValid (a :*: b) = gIsValid a && gIsValid b
     gValidate (a :*: b) = gValidate a `mappend` gValidate b
 
 instance (GValidity a, GValidity b) => GValidity (a :+: b) where
-    gIsValid (L1 x) = gIsValid x
-    gIsValid (R1 x) = gIsValid x
     gValidate (L1 x) = gValidate x
     gValidate (R1 x) = gValidate x
 
 instance (GValidity a, Datatype c) => GValidity (M1 D c a) where
-    gIsValid (M1 x) = gIsValid x
     gValidate m1 = gValidate (unM1 m1)
 
 instance (GValidity a, Constructor c) => GValidity (M1 C c a) where
-    gIsValid (M1 x) = gIsValid x
     gValidate m1 = gValidate (unM1 m1) `annotateValidation` conName m1
 
 instance (GValidity a, Selector c) => GValidity (M1 S c a) where
-    gIsValid (M1 x) = gIsValid x
     gValidate m1 = gValidate (unM1 m1) `annotateValidation` selName m1
 
 instance (Validity a) => GValidity (K1 R a) where
-    gIsValid (K1 x) = isValid x
     gValidate (K1 x) = validate x
 
 -- | Check whether 'isInvalid' is not valid.
diff --git a/test/Data/ValiditySpec.hs b/test/Data/ValiditySpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Data/ValiditySpec.hs
@@ -0,0 +1,61 @@
+{-# LANGUAGE DeriveGeneric #-}
+
+module Data.ValiditySpec
+    ( spec
+    ) where
+
+import GHC.Generics (Generic)
+
+import Data.Monoid
+
+import Data.Validity
+
+import Test.Hspec
+
+data Wrong
+    = Wrong
+    | Fine
+    deriving (Show, Eq)
+
+instance Validity Wrong where
+    validate w =
+        case w of
+            Wrong -> invalid "Wrong"
+            Fine -> valid
+
+data GeneratedValidity =
+    G Double
+      Double
+    deriving (Show, Eq, Generic)
+
+instance Validity GeneratedValidity
+
+-- To make sure that the <?!> operator have the right fixity
+data ManuallyInstantiated =
+    M Double
+      Double
+    deriving (Show, Eq)
+
+instance Validity ManuallyInstantiated where
+    validate (M m1 m2) = annotate m1 "m1" <> annotate m2 "m2"
+
+-- To make sure that the <?@> operator have the right fixity
+data TwoEvens =
+    E Int
+      Int
+    deriving (Show, Eq)
+
+instance Validity TwoEvens where
+    validate (E e1 e2) =
+        declare "e1 is even" (even e1) <> declare "e2 is even" (even e2)
+
+spec :: Spec
+spec = do
+    describe "Wrong" $ do
+        it "says Wrong is invalid" $ Wrong `shouldSatisfy` (not . isValid)
+        it "says Fine is valid" $ Fine `shouldSatisfy` isValid
+    describe "GeneratedValidity" $ do
+        let nan = read "NaN"
+        it "says G nan 0 is not valid" $ G nan 0 `shouldSatisfy` (not . isValid)
+        it "says G 0 nan is not valid" $ G 0 nan `shouldSatisfy` (not . isValid)
+        it "says G 0 0 is valid" $ G 0 0 `shouldSatisfy` isValid
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
diff --git a/validity.cabal b/validity.cabal
--- a/validity.cabal
+++ b/validity.cabal
@@ -2,10 +2,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: d851f0e11791eff6a09f991a6e35b970714b50ddc6ee5f5f97692176076d3fc5
+-- hash: a87e6dba549df499f2c199dd442f9cceacbeb4a8f99bd95f89739fbe810db31a
 
 name:           validity
-version:        0.4.0.4
+version:        0.5.0.0
 synopsis:       Validity typeclass
 description:    For more info, see <https://github.com/NorfairKing/validity the readme>.
                 .
@@ -35,7 +35,7 @@
 bug-reports:    https://github.com/NorfairKing/validity/issues
 author:         Tom Sydney Kerckhove
 maintainer:     syd.kerckhove@gmail.com
-copyright:      Copyright: (c) 2016 Tom Sydney Kerckhove
+copyright:      Copyright: (c) 2016-2018 Tom Sydney Kerckhove
 license:        MIT
 license-file:   LICENSE
 build-type:     Simple
@@ -56,5 +56,20 @@
       Data.RelativeValidity
       Data.Validity
   other-modules:
+      Paths_validity
+  default-language: Haskell2010
+
+test-suite validity-test
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
+  hs-source-dirs:
+      test
+  ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
+  build-depends:
+      base
+    , hspec
+    , validity
+  other-modules:
+      Data.ValiditySpec
       Paths_validity
   default-language: Haskell2010
