Changes between Initial Version and Version 2 of Ticket #106
- Timestamp:
- 04/06/06 09:54:20 (7 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
Ticket #106
- Property impact changed from normal to minor
- Property topic changed from Unclassfied to Expressions & Patterns
- Property adopt changed from to probably yes
- Property summary changed from Adding deepSeq to Haskell' beside seq. to Adding deepSeq/strict to Haskell' beside seq.
-
Ticket #106 – description
initial v2 1 I'd like to propose a deepSeq for Haskell'. 1 We are considering deepSeq for Haskell'. 2 3 === Benefits === 2 4 3 5 * It provides a mechanism to allow an effective, systematic tracking down of a class of space leaks. … … 8 10 * It will open up various optimization opportunities, avoiding building thunks. (I dont talk about this more, but I'm happy to elaborate) 9 11 * It can have an efficient implementation, or a simple (slow) implementation. (The fast implementation one can be used to stomp space leaks, the slow one can help find the same leaks.) 12 * We can ensure that there are no exceptions hiding inside a data structure. 13 * We can throw an exception, and know that there are no exceptions hidding inside it. (are there exceptions in Haskell'?) 10 14 11 What I would like to propose for Haskell' are four things: 15 === Proposal === 16 17 What is being proposes for Haskell' are four things: 12 18 13 19 Essential:: 14 Add a deepSeqfunction into Haskell'20 Add a strict function into Haskell' 15 21 16 22 {{{ 17 deepSeq :: a -> b -> b 23 strict :: a -> a 18 24 }}} 19 25 20 26 * I do not really care if its in a class or not; would prefer not for the reasons John Hughes talked about. 21 * This would deepSeq all its children for regular constructors.22 * deepSeqwould not indirect into IO or MVar.27 * This would Deep Seq all its children for regular constructors. 28 * strict would not indirect into IO or MVar. 23 29 * functions would be evaluated to (W?)HNF. 24 * IO, ST are functions under the hood for the purpose of deepSeq.30 * IO, ST are functions under the hood for the purpose of strict. 25 31 26 32 Easy:: 27 Add a $!! function, and a strictfunction33 Add a $!! function, and a deepSeq function 28 34 29 35 {{{ 30 f $!! a = a `deepSeq` f a31 strict a = a `deepSeq` a 36 f $!! a = strict a `seq` f a 37 deepSeq a b = strict a `seq` b 32 38 }}} 39 40 41 We use strict as our primitive, rather than deepSeq. 42 The expressions (x `deepSeq` y `deepSeq` z) and (strict x `seq` strict y `seq` z) are equivalent, but only the latter makes it clear that z doesn't get fully evaluated. 43 33 44 34 45 Nice:: … … 48 59 We could also do this for ! 49 60 50 --------------51 61 52 Implementation: 62 === Implementation === 53 63 {{{ 54 deepSeq a b = strict# a `seq` b 64 strict :: a -> a 65 strict a@(RAW_CONS <is_deep_seq'd_bit> ... fields )) = 66 if <is_deep_seq'd_bit> == True 67 then return a /* hey, we've already deepSeq'd this */ 68 else do strict# (field_1) 69 strict# (field_2) 70 ... 71 strict# (field_N) 72 /* we set the test bit after the recursive calls */ 73 set <is_deep_seq'd_bit> to True. 74 return a 55 75 56 strict# (RAW_CONS <is_deep_seq'd_bit> ... fields )) = 57 if <is_deep_seq'd_bit> == True 58 then return /* hey, we've already deepSeq'd this */ 59 else set <is_deep_seq'd_bit> to True. 60 deepSeq (field_1) 61 ... 62 deepSeq (field_n) 63 strict# (REF/MVAR...) = return 76 strict a@(REF/MVAR...) = return a 64 77 }}} 65 78 66 So we only deepSeq any specific constructor once! Sorta like lazy evaluation :-) We'd need to catch exceptions, unset the is_deep_seq'd_bit, so that any subsequent call of deepSeq would also have the option of raising the exception. 79 We check the deep_seq'd but *after* evaluating children. 80 * This Stops the (mis)use of strict to observe cycles. 81 * With this order, we do not need to catch exceptions. 82 83 84 === Issues === 85 86 87 * Should there be a DeepSeq class? 88 * Perhaps have an unsafeStrict :: a -> IO a, that tags the deep_seq'd bit when descending. 89 90 * What would you expect to happen here? 91 92 {{{f x xs = let g y = x+y in map !! g xs}}} 93 94 Here I'm evaluating the function g hyperstrictly before the call 95 to map. Does x, the free variable in g's function closure, get evaluated? 96 * Should we have the property 97 {{{strict g === strict . g . strict}}} 98 * Another option would be for the DeepSeq class (or whatver) have a depth limited version, 99 100 {{{ 101 deepSeqSome :: DeepSeq a => Int -> a -> a 102 }}} 103 104 which would only traverse a limited depth into a structure.
