[Haskell-cafe] "Hey! Monad! Leave my Pure alone!"

Scott Michel scooter.phd at gmail.com
Tue Apr 25 21:32:24 UTC 2023


For a number of years, I've been hacking on a Z80 processor simulator, on
and off. It's generally pure code that resembles and uses State, et. al.
The design issue I've run into is adding devices to the memory system,
unsurprisingly typed as MemorySystem. Devices like to do I/O, which
potentially "pollutes" a design with Monads. So... I'm soliciting
suggestions that allow me to isolate Monadic code in the middle of pure
code (which might be Quixotic, but I'll accept that risk.)

MemorySystem uses interval maps containing memory regions, and a memory
region can be a RAMRegion, ROMRegion or DeviceRegion. The abbreviated data
declarations are:

type MemRegionMap addrType wordType = IM.IntervalMap addrType (MemoryRegion
addrType wordType)

data MemorySystem addrType wordType where
  MSys ::
    { _regions    :: MemRegionMap addrType wordType
    } -> MemorySystem addrType wordType

data MemoryRegion addrType wordType where
  EmptyRegion :: MemoryRegion addrType wordType
  RAMRegion :: {- ... -}
  ROMRegion :: {- ... -}
  DevRegion :: {- ... -}

RAMRegion-s and ROMRegion-s are unboxed vector containers, which makes
reading and writing to them pure State code, i.e., the last two function
arguments to the reading function are "MemorySystem ... -> (Vector
wordType, MemorySystem ...)", viz:

type MemReadN addrType wordType = (Vector wordType, MemorySystem addrType
wordType)
mReadN :: addrType
       -- ^ Starting address
       -> Int
       -- ^ Number of words to read
       -> MemorySystem addrType wordType
       -- ^ The memory system from which to read
       -> MemReadN addrType wordType

Supporting DevRegion-s gets more complicated, because I/O is involved (we
like consoles on our machines, yes, we do.) I'd like to keep the reader
signature without unnecessarily injecting a Monad or Monad Transformer into
MemoryRegion and MemorySystem, thereby keeping the Monad or transformer
isolated in DevRegion. For example, an internal device reader  function
would have a signature similar to "... -> Device m devType -> (Vector
wordType, m devType)" instead of "... -> Device m devType -> m (Vector
WordType, devType)", where "m" is the Monad or transformer.

I know, it's hard to jailbreak things out of a Monad, which may be
answering my own question. However, it seems to me that this kind of
problem occurs in real world Haskell, and I haven't encountered the real
world solution.

Ideas?


-scooter
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20230425/a7468ff9/attachment.html>


More information about the Haskell-Cafe mailing list