TreeObservation.hs (1405B)
1 -- Full-result observation is deliberately separate from normal evaluation. 2 module TreeObservation (forceTreeShared) where 3 4 import Control.Exception (evaluate) 5 import qualified Data.IntMap.Strict as IntMap 6 import Runtime (T(..)) 7 import System.Mem.StableName (StableName, makeStableName, hashStableName) 8 9 data Visit = Enter T | Leave (StableName T) 10 11 -- | Force a finite tree, avoiding repeated traversal of physically shared nodes. 12 -- Names are taken after WHNF; hash collisions are resolved by name equality. 13 -- Only completed subtrees are cached, so cycles are not mistaken for finite 14 -- normal forms. Infinite inputs still require an external resource budget. 15 -- The memo is local, and the explicit work stack avoids host recursion by depth. 16 forceTreeShared :: T -> IO () 17 forceTreeShared root = go IntMap.empty [Enter root] 18 where 19 go _ [] = pure () 20 go seen (Leave name : rest) = 21 go (IntMap.insertWith (++) (hashStableName name) [name] seen) rest 22 go seen (Enter input : rest) = do 23 tree <- evaluate input 24 name <- makeStableName tree 25 if name `elem` IntMap.findWithDefault [] (hashStableName name) seen 26 then go seen rest 27 else let done = Leave name : rest 28 in case tree of 29 Leaf -> go seen done 30 Stem child -> go seen (Enter child : done) 31 Fork left right -> go seen (Enter left : Enter right : done)