list of results monad

Hannah Schroeter uk1o@rz.uni-karlsruhe.de
Mon, 12 Mar 2001 02:28:11 +0100


Hello!

On Fri, Mar 09, 2001 at 06:32:11PM +0000, G Murali wrote:
> hi,

> I'm trying to build a monad that will give a list of results.
> this is what i want to be able to do

> I have

> data M a = I [a]

> instance Monad M where

> return x = I [x]
> I (x:xs) >>= f = ??

> The type of >>= is m a -> (a -> m b) -> m b
> but here the input is [a], now if I apply the input individually on f then i 
> can get a [m b] and if i extract at each step then I can get [b] and then if 
> i say return ([b]) i get m b.. right ??

> Is this how I go about it .. if so can you give me a small code snippet of 
> how to do that.

Seems you have a different take on monads than me. For me that
which you give to "return" is to be threaded to the next action,
not to some end result of the whole computation.

I *did* do a result monad once (for data compression, in fact
the monad was combined for "imperatively" consuming input as well
as "imperatively" producing output).

In principle, a result monad is a state monad where the state
is the accumulated output. An input+result monad is a state monad
where the state is a tuple of remaining input and accumulated output.

So, I'd do something like this:

data ResultM r a = RM (r -> (r,a))

instance Monad (ResultM r) where
	return x = RM $ \oldResult -> (oldResult, x)
	(RM m1) >>= fm2 = RM$ \oldResult ->
		case m1 oldResult of
			(result', a) -> case fm2 a of
				RM m2 -> m2 result'
	-- (>>) is defaulted!
	mfail s = error s
	-- if you want to have "exception handling" for mfail, you'd
	-- need to have RM (r -> Either String (r,a)) above

changeResult :: (r -> r) -> RM r ()
changeResult changeFn = RM $ \oldResult -> (changeFn oldResult, ())

runResultM :: ResultM r a -> r -> (r,a)
runResultM (RM f) initRes = f initRes

-- with Lists:

runListResultM m = runResultM m []

addResult :: r -> RM [r] ()
addResult element = RM $ \oldResult -> (oldResult ++ [element], ())

-- with functions to finally yield lists (like shows)

runListFnM :: ResultM ([r] -> [r]) a -> ([r], a)
runListFnM (RM m) = case m id of
	(listFn, a) -> (listFn [], a)

addFnResult :: r -> RM ([r] -> [r]) ()
addFnResult x = RM $ \oldRes -> (oldRes . (x:), ())

Usage:

someComputation = do
	somehow compute x
	addFnResult x
	...
	addFnResult y
	...
	return z

... runListFnM someComputation === ([x,y], z)

Kind regards,

Hannah.