extra type restrictions wanted?

Erik Zuurbier F.S.A.Zuurbier@inter.nl.net
Thu, 1 Jan 1998 20:01:08 +0100 (MET)


/*  One of the example programs in the Object IO library contains the
    general function smap:

smap :: ((.s,.x) -> (.s,.y)) !(.s,![.x]) -> (!.s,![.y])
smap f (s,[x:xs])
    # (s,y ) = f (s,x)
      (s,ys) = smap f (s,xs)
    = (s,[y:ys])
smap _ (s,_)
    = (s,[])
    
    Because of the order of the tuple elements, I think that this
    function first computes the final value of s and only thereafter
    releases the y-list. That makes it impossible to make this function
    run in constant space. Very long lists may cause a 'heap full' error.
        (Is this correct reasoning?)
        
    Therefore I reversed the order of the tuple-elements. I also renamed
    smap to mapFold, as it really combines map and fold: */
        
mapFold :: (a -> !.state -> (b,.state)) ![a] !.state -> ([b],.state)
mapFold fun [a:as] state 
    # (b,state)      = fun a state
      (bs,state)     = mapFold fun as state
    = ([b:bs],state)
mapFold fun [] state = ([],state)

/*  This can run in constant space, delivering the output list elements
    one by one to be further processed and discarded. But constant space
    is achieved only if the 'state' parameter is strict in its components,
    as in the example below.
*/    

import StdEnv

:: *State = {sum :: !Int, count :: !Int}
Start :: ([Int],State)
Start = mapFold fun [1..10000] {sum=0,count=0}
where   fun:: Int State -> (Int,State)
        fun x {sum,count} = (x,{sum=sum+x,count=count+1})
        
/*  My question is: if I regard it as the 'responsibility' of mapFold to
    run in constant space, can I somehow rewrite it so that it will
    actually do that, no matter what the type-details of the state parameter
    are and independent of the fun-function? 

    Maybe it would be nice to be able to restrict application of mapFold
    to state-parameters with strict components, in the spirit of class
    restrictions.

    Regards Erik Zuurbier
*/