diff --git a/CHANGES.txt b/CHANGES.txt
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,8 @@
 Changelog for Extra
 
+1.7.5, released 2020-08-12
+    #65, add Data.Foldable.Extra
+    #65, add sum', product', sumOn' and productOn'
 1.7.4, released 2020-07-15
     #59, add whileJustM and untilJustM
     #61, optimise nubOrd (10% or so)
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -21,3 +21,7 @@
 ## Base versions
 
 A mapping between `base` versions and GHC compiler versions can be found [here](https://wiki.haskell.org/Base_package#Versions).
+
+## Contributing
+
+My general contribution preferences are [available here](https://github.com/ndmitchell/neil#contributions). In addition, this repo contains some generated code which is checked in, namely [src/Extra.hs](src/Extra.hs) and [test/TestGen.hs](test/TestGen.hs). You can generate those files by either running `runhaskell Generate.hs` or `ghci` (which uses the [`.ghci` file](.ghci)) and typing `:generate`. All PR's should contain regenerated versions of those files.
diff --git a/extra.cabal b/extra.cabal
--- a/extra.cabal
+++ b/extra.cabal
@@ -1,7 +1,7 @@
 cabal-version:      >= 1.18
 build-type:         Simple
 name:               extra
-version:            1.7.4
+version:            1.7.5
 license:            BSD3
 license-file:       LICENSE
 category:           Development
diff --git a/src/Data/List/Extra.hs b/src/Data/List/Extra.hs
--- a/src/Data/List/Extra.hs
+++ b/src/Data/List/Extra.hs
@@ -28,6 +28,8 @@
     nubOn, groupOn,
     nubSort, nubSortBy, nubSortOn,
     maximumOn, minimumOn,
+    sum', product',
+    sumOn', productOn',
     disjoint, disjointOrd, disjointOrdBy, allSame, anySame,
     repeatedly, firstJust,
     concatUnzip, concatUnzip3,
@@ -454,6 +456,32 @@
 groupSortBy :: (a -> a -> Ordering) -> [a] -> [[a]]
 groupSortBy f = groupBy (\a b -> f a b == EQ) . sortBy f
 
+
+-- | A strict version of 'sum'.
+--   Unlike 'sum' this function is always strict in the `Num` argument,
+--   whereas the standard version is only strict if the optimiser kicks in.
+--
+-- > sum' [1, 2, 3] == 6
+sum' :: (Num a) => [a] -> a
+sum' = foldl' (+) 0
+
+-- | A strict version of 'sum', using a custom valuation function.
+--
+-- > sumOn' read ["1", "2", "3"] == 6
+sumOn' :: (Num b) => (a -> b) -> [a] -> b
+sumOn' f = foldl' (\acc x -> acc + f x) 0
+
+-- | A strict version of 'product'.
+--
+-- > product' [1, 2, 4] == 8
+product' :: (Num a) => [a] -> a
+product' = foldl' (*) 1
+
+-- | A strict version of 'product', using a custom valuation function.
+--
+-- > productOn' read ["1", "2", "4"] == 8
+productOn' :: (Num b) => (a -> b) -> [a] -> b
+productOn' f = foldl' (\acc x -> acc * f x) 1
 
 -- | Merge two lists which are assumed to be ordered.
 --
diff --git a/src/Extra.hs b/src/Extra.hs
--- a/src/Extra.hs
+++ b/src/Extra.hs
@@ -23,7 +23,7 @@
     writeIORef', atomicWriteIORef', atomicModifyIORef_, atomicModifyIORef'_,
     -- * Data.List.Extra
     -- | Extra functions available in @"Data.List.Extra"@.
-    lower, upper, trim, trimStart, trimEnd, word1, line1, escapeHTML, escapeJSON, unescapeHTML, unescapeJSON, dropEnd, takeEnd, splitAtEnd, breakEnd, spanEnd, dropWhileEnd', takeWhileEnd, stripSuffix, stripInfix, stripInfixEnd, dropPrefix, dropSuffix, wordsBy, linesBy, breakOn, breakOnEnd, splitOn, split, chunksOf, headDef, lastDef, notNull, list, unsnoc, cons, snoc, drop1, dropEnd1, mconcatMap, enumerate, groupSort, groupSortOn, groupSortBy, nubOrd, nubOrdBy, nubOrdOn, nubOn, groupOn, nubSort, nubSortBy, nubSortOn, maximumOn, minimumOn, disjoint, disjointOrd, disjointOrdBy, allSame, anySame, repeatedly, firstJust, concatUnzip, concatUnzip3, zipFrom, zipWithFrom, zipWithLongest, replace, merge, mergeBy,
+    lower, upper, trim, trimStart, trimEnd, word1, line1, escapeHTML, escapeJSON, unescapeHTML, unescapeJSON, dropEnd, takeEnd, splitAtEnd, breakEnd, spanEnd, dropWhileEnd', takeWhileEnd, stripSuffix, stripInfix, stripInfixEnd, dropPrefix, dropSuffix, wordsBy, linesBy, breakOn, breakOnEnd, splitOn, split, chunksOf, headDef, lastDef, notNull, list, unsnoc, cons, snoc, drop1, dropEnd1, mconcatMap, enumerate, groupSort, groupSortOn, groupSortBy, nubOrd, nubOrdBy, nubOrdOn, nubOn, groupOn, nubSort, nubSortBy, nubSortOn, maximumOn, minimumOn, sum', product', sumOn', productOn', disjoint, disjointOrd, disjointOrdBy, allSame, anySame, repeatedly, firstJust, concatUnzip, concatUnzip3, zipFrom, zipWithFrom, zipWithLongest, replace, merge, mergeBy,
     -- * Data.List.NonEmpty.Extra
     -- | Extra functions available in @"Data.List.NonEmpty.Extra"@.
     (|:), (|>), appendl, appendr, maximum1, minimum1, maximumBy1, minimumBy1, maximumOn1, minimumOn1,
diff --git a/test/TestGen.hs b/test/TestGen.hs
--- a/test/TestGen.hs
+++ b/test/TestGen.hs
@@ -172,6 +172,10 @@
     testGen "\\xs -> concatMap snd (groupSort xs) == map snd (sortOn fst xs)" $ \xs -> concatMap snd (groupSort xs) == map snd (sortOn fst xs)
     testGen "groupSortOn length [\"test\",\"of\",\"sized\",\"item\"] == [[\"of\"],[\"test\",\"item\"],[\"sized\"]]" $ groupSortOn length ["test","of","sized","item"] == [["of"],["test","item"],["sized"]]
     testGen "groupSortBy (compare `on` length) [\"test\",\"of\",\"sized\",\"item\"] == [[\"of\"],[\"test\",\"item\"],[\"sized\"]]" $ groupSortBy (compare `on` length) ["test","of","sized","item"] == [["of"],["test","item"],["sized"]]
+    testGen "sum' [1, 2, 3] == 6" $ sum' [1, 2, 3] == 6
+    testGen "sumOn' read [\"1\", \"2\", \"3\"] == 6" $ sumOn' read ["1", "2", "3"] == 6
+    testGen "product' [1, 2, 4] == 8" $ product' [1, 2, 4] == 8
+    testGen "productOn' read [\"1\", \"2\", \"4\"] == 8" $ productOn' read ["1", "2", "4"] == 8
     testGen "merge \"ace\" \"bd\" == \"abcde\"" $ merge "ace" "bd" == "abcde"
     testGen "\\xs ys -> merge (sort xs) (sort ys) == sort (xs ++ ys)" $ \xs ys -> merge (sort xs) (sort ys) == sort (xs ++ ys)
     testGen "replace \"el\" \"_\" \"Hello Bella\" == \"H_lo B_la\"" $ replace "el" "_" "Hello Bella" == "H_lo B_la"
