diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,7 @@
+## 1.4.5
+
+* Foldable/Traversable instances for FormResult [#1089](https://github.com/yesodweb/yesod/pull/1089)
+
 ## 1.4.4.1
 
 * runFormPost has wrong behavior for empty forms [#950](https://github.com/yesodweb/yesod/issues/950)
diff --git a/Yesod/Form/Functions.hs b/Yesod/Form/Functions.hs
--- a/Yesod/Form/Functions.hs
+++ b/Yesod/Form/Functions.hs
@@ -228,9 +228,10 @@
                     | not (Map.lookup tokenKey params === reqToken req) ->
                         FormFailure [renderMessage m langs MsgCsrfWarning]
                 _ -> res
+            -- It's important to use constant-time comparison (constEqBytes) in order to avoid timing attacks.
             where (Just [t1]) === (Just t2) = TE.encodeUtf8 t1 `constEqBytes` TE.encodeUtf8 t2
-                  Nothing     === Nothing   = True   -- It's important to use constTimeEq
-                  _           === _         = False  -- in order to avoid timing attacks.
+                  Nothing     === Nothing   = True
+                  _           === _         = False
     return ((res', xml), enctype)
 
 -- | Similar to 'runFormPost', except it always ignores the currently available
diff --git a/Yesod/Form/Types.hs b/Yesod/Form/Types.hs
--- a/Yesod/Form/Types.hs
+++ b/Yesod/Form/Types.hs
@@ -35,6 +35,8 @@
 import Yesod.Core
 import qualified Data.Map as Map
 import Data.Semigroup (Semigroup, (<>))
+import Data.Traversable
+import Data.Foldable
 
 -- | A form can produce three different results: there was no data available,
 -- the data was invalid, or there was a successful parse.
@@ -61,6 +63,20 @@
     mappend x y = mappend <$> x <*> y
 instance Semigroup m => Semigroup (FormResult m) where
     x <> y = (<>) <$> x <*> y
+
+-- | @since 1.4.5
+instance Foldable FormResult where
+    foldMap f r = case r of
+      FormSuccess a -> f a
+      FormFailure errs -> mempty
+      FormMissing -> mempty
+
+-- | @since 1.4.5
+instance Traversable FormResult where
+    traverse f r = case r of
+      FormSuccess a -> fmap FormSuccess (f a)
+      FormFailure errs -> pure (FormFailure errs)
+      FormMissing -> pure FormMissing
 
 -- | The encoding type required by a form. The 'ToHtml' instance produces values
 -- that can be inserted directly into HTML.
diff --git a/yesod-form.cabal b/yesod-form.cabal
--- a/yesod-form.cabal
+++ b/yesod-form.cabal
@@ -1,5 +1,5 @@
 name:            yesod-form
-version:         1.4.4.1
+version:         1.4.5
 license:         MIT
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
