[Haskell-beginners] Is there such a thing as a lazy monadic list?

Arlen Cuss celtic at sairyx.org
Mon May 9 10:41:12 CEST 2011


Hi all,

I'm currently trying to write a very simple VM in order to learn and
stretch my Haskell. I'm currently up against a problem.

I'm using an (IOUArray Int Word32) to represent the memory of a VM
instance. This is all fine so far, but now I'm trying to write a
'disassemble' function that will disassemble an instruction starting
from a given location in memory.

Ideally I could write a function that would lazily yield successive
elements from memory, sort of like this:

> readVMFrom :: VM -> Address -> IO [Word32]
> readVMFrom v f = do
>   i <- readArray (memory v) f
>   rest <- readVMFrom v (succ f)
>   return $ i : readVMFrom v (succ f)

Of course, this isn't lazy, and so happily runs off the end of memory
each time. (I could stop that, but that's not the point!) I'm not sure
how to lazily construct a list in IO.

My next thought is to instead make a function to return an action that
yields successive values of memory, given some start, i.e. something
like:

> readVMFrom :: VM -> Address -> IO Word32

.. but I'm thinking I might have to do some StateT nonsense in order to
actually keep track of which index we want to read next. (subtext: I
don't know how to do that!)

So I then think that perhaps I can do this by having readVMFrom return
an action which yields a) the next value, b) the address of the next
value (so we know how much we ate), and c) an action to yield the next
value and action and so on, so on. I managed that this way (WARNING,
BEGINNER HASKELL CODE FOLLOWS):

> newtype RVFResult = RVFResult { getRVFResult :: (Word32, Address, IO
RVFResult) }
>
> readVMFrom :: VM -> Address -> IO RVFResult
> readVMFrom v f = do
>   i <- readArray (memory v) f
>   return $ RVFResult (i, succ f, readVMFrom v $ succ f)

A function can then take an argument of type RVFResult as an indication
it wants 1..n sequential values from memory:

> disassemble :: RVFResult -> IO (Instruction, Address)
> disassemble r = do
>   let (i, p, a) = getRVFResult r
>   case i of
>     0x01 -> return (Push, p)
>     0x02 -> return (Pop, p)
>     0x03 -> return (Call, p)
>     0x04 -> do
>               r <- a
>               let (v, p, a) = getRVFResult r
>               return (Out v, p)

Here you can see how we consume an additional value by executing the
returned action 'a'. It's damn ugly, and this almost looks like the
place for a monad (possibly something involving StateT, though, I don't
know!).

Ideally I'd manage a lazily constructed list -- somehow I feel that's
most "Haskelly" -- but does anyone else have any ideas? I kinda fleshed
this last solution out as I wrote this email, so it's kinda cruddy.

Cheers,

Arlen
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part
URL: <http://www.haskell.org/pipermail/beginners/attachments/20110509/5a4f9422/attachment.pgp>


More information about the Beginners mailing list