Determining the extent of lazy evaluation
Given
data BTree a = End
| Node a (BTree a) (BTree a)
deriving(Show,Eq,Ord)
data Msg = Msg { from :: S开发者_运维问答tring
, to :: String
, when :: Int
, message :: String }
instance Ord Msg where
compare a b = (when a) `compare` (when b)
instance Eq Msg where
(==) a b = (when a) == (when b)
My function to count nodes (which seems off but that's aside from the question) is
count :: (Ord a) => (BTree a) -> Int
count = sum . count'
where
count' :: (Ord a) => (BTree a) -> [Int]
count' End = []
count' (Node _ l r) =
[1] ++ (count' l) ++ (count' r)
Does count
not evaluate the contents of the Msg
by virtue of its value being discarded by _
? Perhaps a better question is, how do I know where lazy evaluation starts and ends for this sort of thing?
If the third line of count'
was:
count' (Node (Msg x _ _ _) l r) =
Can I assume that the other three fields of Msg
were accessed/evaluated, or does lazy evaluation go that far?
No. The fields of a data structure are evaluated lazily by default. Since you're not using the other fields in any way, they will not be evaluated by this code. If you want to make it so that evaluating a node forces all its fields to be evaluated, you can add strictness annotations to the fields:
data BTree a = End
| Node !a (BTree a) (BTree a)
deriving(Show,Eq,Ord)
data Msg = Msg { from :: !String
, to :: !String
, when :: !Int
, message :: !String }
Since counting the nodes forces the nodes themselves to be evaluated, this will also force the node values to be evaluated. If you only want this behavior for your one function, you can force evaluation in a more fine-grained manner using seq
:
count' (Node x l r) = x `seq` ([1] ++ count' l ++ count' r)
or a bang pattern (requires the BangPatterns
extension)
count' (Node !x l r) = [1] ++ count' l ++ count' r
精彩评论