diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,16 @@
 # Revision history for property-matchers
 
-## 0.2.0.0
+## 0.3
+* Add `fails` function, for asserting that an exception is thrown
+* Replace `propful` with `alignExact`
+* Add `alignLax` generalizing `alignExact`
+* Add `elem`
+* Add fixity for `:=>` to be compatible with `?`
+* Add comparisons other than `equals`
 
+
+## 0.2
+
 * Add `bool` function
 * Add hspec + smallcheck test suite
 * Add `branch` for non-backtracking disjunction of properties
@@ -12,7 +21,7 @@
 * Reorder `PropertyMatchers` module for intelligibility
 
 
-## 0.1.0.0
+## 0.1
 
 * Rename to property-matchers
 * Rename kth to atIndex
diff --git a/property-matchers.cabal b/property-matchers.cabal
--- a/property-matchers.cabal
+++ b/property-matchers.cabal
@@ -1,7 +1,7 @@
 cabal-version: 2.4
 
 name: property-matchers
-version: 0.2.0.0
+version: 0.3.0.0
 synopsis: A library for tests, based on transforming and writing properties
 description:
   This package provides ways to write properties for testing such that they compose nicely and are easy to debug.
@@ -25,7 +25,9 @@
    ,recover-rtti >= 0.3 && < 0.6
    ,pretty-simple >= 1.1 && < 4.2
    ,prettyprinter >= 1.6 && < 2.0
+   ,semialign >= 1 && < 2
    ,text >= 1.0 && < 2.2
+   ,these >= 1 && < 2
   if !impl(ghc >= 8.0)
     build-depends:
       semigroups >= 0.8.4 && < 1
diff --git a/src/PropertyMatchers.hs b/src/PropertyMatchers.hs
--- a/src/PropertyMatchers.hs
+++ b/src/PropertyMatchers.hs
@@ -38,30 +38,38 @@
   , match
   , atIndex
   , list
-  , propful
+  , alignExact
+  , alignLax
+  , elem
   , compose
   , allTrue
   , allOf1
   , pair
   , fun
+  , fails
   , traced
   , tracedShow
   , traceFailShow
   , traceFail
   , forced
   , equals
+  , lt
+  , lte
+  , gt
+  , gte
   , bool
   , pattern (:=>)
   , (?)
   )
   where
 
-import Prelude hiding (and, fail, or)
+import Prelude hiding (and, elem, fail, or)
 import Control.Concurrent (myThreadId)
 import Control.Exception
-import Control.Monad hiding (fail)
+import qualified Data.Align as Align
 import Data.Foldable (toList)
 import Data.Functor.Const
+import Data.These
 import Data.Typeable
 import Debug.Trace
 import GHC.Stack
@@ -255,20 +263,53 @@
   where
   psl = length ps
 
--- | Given a functor-full of properties, and a functor-full of values, ensure
--- that the structures of the two functors match and apply all of the properties
--- to all of the values.
+-- | Given a functor-full of properties, and a functor-full of values, align
+-- the two together and apply all of the properties to the values pointwise.
+-- If there is any misalignment between the two, fail.
 -- Generalized version of `list`.
-propful ::
-  (HasCallStack, Eq (f ()), Functor f, Foldable f) =>
+alignExact
+  :: (HasCallStack, Traversable f, Align.Semialign f) =>
   f (Prop a) ->
   Prop (f a)
-propful props values
-  | void props == void values =
-    list (toList props) (toList values)
-  | otherwise =
-    fail ("shape equal to that of" <> PP.pretty (anythingToTextPretty props)) values
+alignExact props values =
+  sequence_ $ Align.alignWith
+    (\case
+      This _extraProp -> fail ("no extra elements relative to " <> PP.pretty (anythingToTextPretty props)) values
+      That _extraValue -> fail ("no missing elements relative to " <> PP.pretty (anythingToTextPretty props)) values
+      These prop value -> prop value
+      )
+    props values
 
+-- | Given a functor-full of properties and a functor-full of values
+-- (and a property for excess values) align the properties and values and apply
+-- them to each other pointwise. If there is any misalignment between the two:
+--   * if there's an excess value, apply the excess property to it
+--   * if there's a missing value, pass the corresponding property `Nothing`
+-- Examples:
+-- alignLax (Map.fromList ["k" :=> P.lt 3, "g" :=> P.match P.gt 4]) (Map.fromList )
+alignLax
+  :: (Traversable f, Align.Semialign f) =>
+  Prop a ->
+  f (Prop (Maybe a)) ->
+  Prop (f a)
+alignLax excess props values = sequence_ $ Align.alignWith
+  (\case
+    This prop -> prop Nothing
+    That extraValue -> excess extraValue
+    These prop value -> prop (Just value)
+    )
+  props values
+
+-- | Given a property and a traversable functor-full of values,
+-- succeed if the property succeeds on at least one of the values.
+elem
+  :: (HasCallStack, Traversable f) =>
+  Prop a ->
+  Prop (f a)
+elem prop values
+  | null values = fail "nonempty value" values
+  | otherwise = foldr1 or $ prop <$> values
+
 -- | Given a representable functor-full of properties, and a functor-full of values,
 --  yield a representable functor-full of booleans. Similar to `propful`.
 compose ::
@@ -305,6 +346,11 @@
 fun :: (a -> b) -> PT b a
 fun f p = p . f
 
+fails :: Exception e => Prop e -> Prop (IO a)
+fails p actual = trySync actual >>= \case
+  Left e -> p e
+  Right r -> fail "a failed computation" r
+
 -- | Prints the input of a property, if the property fails, using `Show`.
 --   Requires that the property's output type can be checked for failure.
 traceFailShow :: Show a => PT a a
@@ -339,6 +385,26 @@
   | expected == actual = succeed actual
   | otherwise = fail (PP.pretty (anythingToTextPretty expected)) actual
 
+lt :: (HasCallStack, Ord a) => a -> Prop a
+lt expected actual
+  | actual < expected = succeed actual
+  | otherwise = fail ("less than " <> PP.pretty (anythingToTextPretty expected)) actual
+
+gt :: (HasCallStack, Ord a) => a -> Prop a
+gt expected actual
+  | actual > expected = succeed actual
+  | otherwise = fail ("greater than " <> PP.pretty (anythingToTextPretty expected)) actual
+
+gte :: (HasCallStack, Ord a) => a -> Prop a
+gte expected actual
+  | actual >= expected = succeed actual
+  | otherwise = fail ("greater than/equal to " <> PP.pretty (anythingToTextPretty expected)) actual
+
+lte :: (HasCallStack, Ord a) => a -> Prop a
+lte expected actual
+  | actual <= expected = succeed actual
+  | otherwise = fail ("less than/equal to " <> PP.pretty (anythingToTextPretty expected)) actual
+
 bool :: HasCallStack => Bool -> Assertion
 bool b
   | b = succeed b
@@ -349,6 +415,7 @@
 -- `(x :: Either Int Int) & branch [match _Left :=> equals 1, match _Right :=> equals 2]`
 pattern (:=>) :: a -> b -> (a, b)
 pattern a :=> b = (a, b)
+infixr 7 :=>
 
 -- | Higher precedence '$', to work well with '&'.
 -- The intended use is something like `x & match _Right ? equals 2`.
