diff options
author | David Feuer <David.Feuer@gmail.com> | 2014-10-01 15:02:33 +0200 |
---|---|---|
committer | Joachim Breitner <mail@joachim-breitner.de> | 2014-10-01 18:20:26 +0200 |
commit | 488e95b433d4f7568aa89622c729e64aa3b6520d (patch) | |
tree | f4dc22bb66024a31de33c5e588da4ebecbbf0999 /libraries | |
parent | 864bed729eaee9531ada4ba1c869c676893f51bd (diff) | |
download | haskell-488e95b433d4f7568aa89622c729e64aa3b6520d.tar.gz |
Make foldr2 a bit more strict
in order to make its RULES semantics preserving. This fixes #9495.
Diffstat (limited to 'libraries')
-rw-r--r-- | libraries/base/GHC/List.lhs | 43 | ||||
-rw-r--r-- | libraries/base/changelog.md | 4 |
2 files changed, 33 insertions, 14 deletions
diff --git a/libraries/base/GHC/List.lhs b/libraries/base/GHC/List.lhs index ffcc8ab56f..8c8e4bb050 100644 --- a/libraries/base/GHC/List.lhs +++ b/libraries/base/GHC/List.lhs @@ -646,7 +646,7 @@ xs !! (I# n0) | isTrue# (n0 <# 0#) = error "Prelude.(!!): negative index\n" foldr2 :: (a -> b -> c -> c) -> c -> [a] -> [b] -> c foldr2 k z = go where - go [] _ys = z + go [] ys = ys `seq` z -- see #9495 for the seq go _xs [] = z go (x:xs) (y:ys) = k x y (go xs ys) {-# INLINE [0] foldr2 #-} @@ -670,16 +670,6 @@ foldr2_right k _z y r (x:xs) = k x y (r xs) #-} \end{code} -The foldr2/right rule isn't exactly right, because it changes -the strictness of foldr2 (and thereby zip) - -E.g. main = print (null (zip nonobviousNil (build undefined))) - where nonobviousNil = f 3 - f n = if n == 0 then [] else f (n-1) - -I'm going to leave it though. - - Zips for larger tuples are in the List module. \begin{code} @@ -687,10 +677,22 @@ Zips for larger tuples are in the List module. -- | 'zip' takes two lists and returns a list of corresponding pairs. -- If one input list is short, excess elements of the longer list are -- discarded. +-- +-- NOTE: GHC's implementation of @zip@ deviates slightly from the +-- standard. In particular, Haskell 98 and Haskell 2010 require that +-- @zip [x1,x2,...,xn] (y1:y2:...:yn:_|_) = [(x1,y1),(x2,y2),...,(xn,yn)]@ +-- In GHC, however, +-- @zip [x1,x2,...,xn] (y1:y2:...:yn:_|_) = (x1,y1):(x2,y2):...:(xn,yn):_|_@ +-- That is, you cannot use termination of the left list to avoid hitting +-- bottom in the right list. + +-- This deviation is necessary to make fusion with 'build' in the right +-- list preserve semantics. {-# NOINLINE [1] zip #-} zip :: [a] -> [b] -> [(a,b)] +zip [] bs = bs `seq` [] -- see #9495 for the seq +zip _as [] = [] zip (a:as) (b:bs) = (a,b) : zip as bs -zip _ _ = [] {-# INLINE [0] zipFB #-} zipFB :: ((a, b) -> c -> d) -> a -> b -> c -> d @@ -723,10 +725,23 @@ zip3 _ _ _ = [] -- as the first argument, instead of a tupling function. -- For example, @'zipWith' (+)@ is applied to two lists to produce the -- list of corresponding sums. +-- +-- NOTE: GHC's implementation of @zipWith@ deviates slightly from the +-- standard. In particular, Haskell 98 and Haskell 2010 require that +-- @zipWith (,) [x1,x2,...,xn] (y1:y2:...:yn:_|_) = [(x1,y1),(x2,y2),...,(xn,yn)]@ +-- In GHC, however, +-- @zipWith (,) [x1,x2,...,xn] (y1:y2:...:yn:_|_) = (x1,y1):(x2,y2):...:(xn,yn):_|_@ +-- That is, you cannot use termination of the left list to avoid hitting +-- bottom in the right list. + +-- This deviation is necessary to make fusion with 'build' in the right +-- list preserve semantics. + {-# NOINLINE [1] zipWith #-} zipWith :: (a->b->c) -> [a]->[b]->[c] -zipWith f (a:as) (b:bs) = f a b : zipWith f as bs -zipWith _ _ _ = [] +zipWith _f [] bs = bs `seq` [] -- see #9495 for the seq +zipWith _f _as [] = [] +zipWith f (a:as) (b:bs) = f a b : zipWith f as bs -- zipWithFB must have arity 2 since it gets two arguments in the "zipWith" -- rule; it might not get inlined otherwise diff --git a/libraries/base/changelog.md b/libraries/base/changelog.md index 7b168fec5c..7529782492 100644 --- a/libraries/base/changelog.md +++ b/libraries/base/changelog.md @@ -73,6 +73,10 @@ the functions from `Data.List` (in other words, `Data.OldList` corresponds to `base-4.7.0.1`'s `Data.List`) + * `foldr2` (together with `zip` and `zipWith`) is made a bit stricter in the + second argument, so that the fusion RULES for it do not change the + semantics. (#9596) + ## 4.7.0.1 *Jul 2014* * Bundled with GHC 7.8.3 |