Enforcing Strict Evaluation
Hi all, I wrote an application that successively reads the contents of several (big) files, building an intermediate data structure, pretty printing their contents into one accumulated output file and extracting some information from the data structure for further processing. To avoid needing huge heap space the program reads one input file, pretty prints a representation of its contents (big) to the output file (via appendFile), extracts the necessary information (small) and proceeds with that information, so that the data structure representing the file contents can be released. To achieve the latter, however, I need to force strict evaluation of the extraction. My first approach was using $! as follows: ... info <- mapM (apply outfile) files ... apply outfile infile = do result <- read infile -- parses infile and generates data structure of its contents appendFile outfile (show result) return $! (extractInfos result) -- extractInfos returns a list of some sort of information but that did not work. I tried then printing the length of the extracted list because this would require the strict evaluation, and this works: ... info <- mapM (apply outfile) files ... apply outfile infile = do result <- read infile -- parses infile and generates data structure of its contents appendFile outfile (show result) let result' = extractInfos result -- extracts necessary information from result putStrLnFlushed (show (length result')) -- forces evaluation of result'! return result' Why does the first solution not work? How can I achieve the effects of the latter solution without printing something? Thanks, Bernd
The prelude support for strict evaluation, `seq` and ($!), evaluate only enough to ensure that the value being "forced" is not bottom. In your case you need a "deeper" evaluation to be forced. A clean (though somewhat tedious) way to achieve what you need is with the `deepSeq` function from the following module. Dean Herington The `DeepSeq` class provides a method `deepSeq` that is similar to `seq` except that it forces deep evaluation of its first argument before returning its second argument. Instances of `DeepSeq` are provided for Prelude types. Other instances must be supplied by users of this module.
module DeepSeq where
class DeepSeq a where deepSeq :: a -> b -> b deepSeq = seq -- default, for simple cases
infixr 0 `deepSeq`, $!!
($!!) :: (DeepSeq a) => (a -> b) -> a -> b f $!! x = x `deepSeq` f x
instance DeepSeq () where
instance (DeepSeq a) => DeepSeq [a] where deepSeq [] y = y deepSeq (x:xs) y = deepSeq x $ deepSeq xs y
instance (DeepSeq a,DeepSeq b) => DeepSeq (a,b) where deepSeq (a,b) y = deepSeq a $ deepSeq b y instance (DeepSeq a,DeepSeq b,DeepSeq c) => DeepSeq (a,b,c) where deepSeq (a,b,c) y = deepSeq a $ deepSeq b $ deepSeq c y instance (DeepSeq a,DeepSeq b,DeepSeq c,DeepSeq d) => DeepSeq (a,b,c,d) where deepSeq (a,b,c,d) y = deepSeq a $ deepSeq b $ deepSeq c $ deepSeq d y instance (DeepSeq a,DeepSeq b,DeepSeq c,DeepSeq d,DeepSeq e) => DeepSeq (a,b,c,d,e) where deepSeq (a,b,c,d,e) y = deepSeq a $ deepSeq b $ deepSeq c $ deepSeq d $ deepSeq e y instance (DeepSeq a,DeepSeq b,DeepSeq c,DeepSeq d,DeepSeq e,DeepSeq f) => DeepSeq (a,b,c,d,e,f) where deepSeq (a,b,c,d,e,f) y = deepSeq a $ deepSeq b $ deepSeq c $ deepSeq d $ deepSeq e $ deepSeq f y instance (DeepSeq a,DeepSeq b,DeepSeq c,DeepSeq d,DeepSeq e,DeepSeq f,DeepSeq g) => DeepSeq (a,b,c,d,e,f,g) where deepSeq (a,b,c,d,e,f,g) y = deepSeq a $ deepSeq b $ deepSeq c $ deepSeq d $ deepSeq e $ deepSeq f $ deepSeq g y
instance DeepSeq Bool where instance DeepSeq Char where
instance (DeepSeq a) => DeepSeq (Maybe a) where deepSeq Nothing y = y deepSeq (Just x) y = deepSeq x y
instance (DeepSeq a, DeepSeq b) => DeepSeq (Either a b) where deepSeq (Left a) y = deepSeq a y deepSeq (Right b) y = deepSeq b y
instance DeepSeq Ordering where
instance DeepSeq Integer where instance DeepSeq Int where instance DeepSeq Float where instance DeepSeq Double where
participants (2)
-
Bernd Holzmüller -
Dean Herington