Stack usage with a state monad

Graham Klyne gk at ninebynine.org
Fri Jan 2 14:46:04 EST 2004


At 15:37 31/12/03 +0000, Joe Thornber wrote:
>On Wed, Dec 31, 2003 at 02:38:06PM +0000, Graham Klyne wrote:
> >  getOrCachePositionValue pos =
> >     do { mcache <- gets (findPos pos)     -- Query cache for position
> >        ; case mcache of
> >            Just cached -> return (cachedVal cached)  -- Return cached value
> >            Nothing     ->                            -- Not in cache:
> >               do { let val = calculatePosVal pos     -- Calculate new value
> >                  ; modify (addToCache pos val)       -- Cache new value
> >                  ; return val                        -- Return new value
> >                  }
> >        }
> >
> > (This code of off-the-cuff, and may contain errors)
> >
> > My point is that the function 'calculatePosVal' used here to evaluate a
> > position not in the cache simply returns the calculated value, not a
> > monad.  This function is wrapped in "high level" code that queries and/or
> > updates the cache which is kept in a state monad.  Thus, the return 
> type of
> > 'getOrCachePositionValue' would be a monad of the appropriate type.
>
>But I want calculatePosVal to use the cache too :(

Well, maybe you really do need to run your calculation in the state monad, 
but I'll ask one more question:  to you need your 'calculatePosVal' to 
*use* the cache, or to *update* it?  If you simply need access to the 
cache, then the function could accept cache data extracted from the state 
monad as an additional argument; e.g.

   getOrCachePositionValue pos =
      do { cacheState <- get                       -- Get current cache state
         ; let mcache = findPos pos cacheState     -- Query cache for position
         ; case mcache of
             Just cached -> return (cachedVal cached)  -- Return cached value
             Nothing     ->                            -- Not in cache:
                do { let val = calculatePosVal pos cacheState
                                                       -- Calculate new value
                   ; modify (addToCache pos val)       -- Cache new value
                   ; return val                        -- Return new value
                   }
         }

If your calculation really needs to update the cache state as it goes 
along, then I agree that it needs to be run in the state monad.  But even 
then, I'd be inclined to look for sub-calculations that can be evaluated as 
ordinary functions.

Anyway, I think I've probably added enough noise to this debate.  Whatever 
approach you may use, have fun!

#g


------------
Graham Klyne
For email:
http://www.ninebynine.org/#Contact



More information about the Haskell-Cafe mailing list