<div dir="ltr">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.)<div><br></div><div>MemorySystem uses interval maps containing memory regions, and a memory region can be a RAMRegion, ROMRegion or DeviceRegion. The abbreviated data declarations are:<div><br></div><div><div style="color:rgb(0,0,0);font-size:13px;line-height:18px;white-space:pre"><div style="font-family:"DejaVu Sans Mono",Consolas,"Courier New",monospace,Consolas,"Courier New",monospace"><span style="color:rgb(0,0,255)">type</span> <span style="color:rgb(0,0,255)">MemRegionMap</span> <span style="color:rgb(0,16,128)">addrType</span> <span style="color:rgb(0,16,128)">wordType</span> = <span style="color:rgb(38,127,153)">IM.</span><span style="color:rgb(0,0,255)">IntervalMap</span> <span style="color:rgb(0,16,128)">addrType</span> (<span style="color:rgb(0,0,255)">MemoryRegion</span> <span style="color:rgb(0,16,128)">addrType</span> <span style="color:rgb(0,16,128)">wordType</span>)</div><font face="DejaVu Sans Mono, Consolas, Courier New, monospace, Consolas, Courier New, monospace"><br></font><div style="font-family:"DejaVu Sans Mono",Consolas,"Courier New",monospace,Consolas,"Courier New",monospace"><span style="color:rgb(0,0,255)">data</span> <span style="color:rgb(0,0,255)">MemorySystem</span> <span style="color:rgb(0,16,128)">addrType</span> <span style="color:rgb(0,16,128)">wordType</span> <span style="color:rgb(0,0,255)">where</span></div><div style="font-family:"DejaVu Sans Mono",Consolas,"Courier New",monospace,Consolas,"Courier New",monospace">  MSys ::</div><div style="font-family:"DejaVu Sans Mono",Consolas,"Courier New",monospace,Consolas,"Courier New",monospace">    { <span style="color:rgb(0,16,128)">_regions</span>    :: <span style="color:rgb(0,0,255)">MemRegionMap</span> <span style="color:rgb(0,16,128)">addrType</span> <span style="color:rgb(0,16,128)">wordType</span></div><div style="font-family:"DejaVu Sans Mono",Consolas,"Courier New",monospace,Consolas,"Courier New",monospace"><span style="color:rgb(0,128,0)"> </span>   } -> <span style="color:rgb(0,0,255)">MemorySystem</span> <span style="color:rgb(0,16,128)">addrType</span> <span style="color:rgb(0,16,128)">wordType</span></div><font face="DejaVu Sans Mono, Consolas, Courier New, monospace, Consolas, Courier New, monospace"><br></font><div style="font-family:"DejaVu Sans Mono",Consolas,"Courier New",monospace,Consolas,"Courier New",monospace"><span style="color:rgb(0,0,255)">data</span> <span style="color:rgb(0,0,255)">MemoryRegion</span> <span style="color:rgb(0,16,128)">addrType</span> <span style="color:rgb(0,16,128)">wordType</span> <span style="color:rgb(0,0,255)">where</span><br></div><div style="font-family:"DejaVu Sans Mono",Consolas,"Courier New",monospace,Consolas,"Courier New",monospace">  EmptyRegion :: <span style="color:rgb(0,0,255)">MemoryRegion</span> <span style="color:rgb(0,16,128)">addrType</span> <span style="color:rgb(0,16,128)">wordType</span></div><div style="font-family:"DejaVu Sans Mono",Consolas,"Courier New",monospace,Consolas,"Courier New",monospace">  RAMRegion :: {- ... -}</div><div style="font-family:"DejaVu Sans Mono",Consolas,"Courier New",monospace,Consolas,"Courier New",monospace">  ROMRegion :: {- ... -}<br></div><div style="font-family:"DejaVu Sans Mono",Consolas,"Courier New",monospace,Consolas,"Courier New",monospace">  DevRegion :: {- ... -}</div><div style="font-family:"DejaVu Sans Mono",Consolas,"Courier New",monospace,Consolas,"Courier New",monospace"><br></div><span style="color:rgb(34,34,34);font-size:small;white-space:normal">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:</span></div></div></div><div style="color:rgb(0,0,0);font-size:13px;line-height:18px;white-space:pre"><br></div><div style="color:rgb(0,0,0);font-size:13px;line-height:18px;white-space:pre"><div style="font-family:"DejaVu Sans Mono",Consolas,"Courier New",monospace,Consolas,"Courier New",monospace;line-height:18px"><div><span style="color:rgb(0,0,255)">type</span> <span style="color:rgb(0,0,255)">MemReadN</span> <span style="color:rgb(0,16,128)">addrType</span> <span style="color:rgb(0,16,128)">wordType</span> = (<span style="color:rgb(0,0,255)">Vector</span> <span style="color:rgb(0,16,128)">wordType</span>, <span style="color:rgb(0,0,255)">MemorySystem</span> <span style="color:rgb(0,16,128)">addrType</span> <span style="color:rgb(0,16,128)">wordType</span>)<br></div><div style="line-height:18px"><div><span style="color:rgb(121,94,38)">mReadN</span> :: <span style="color:rgb(0,16,128)">addrType</span></div><div><span style="color:rgb(0,128,0)">       -- ^ Starting address</span></div><div>       -> <span style="color:rgb(0,0,255)">Int</span></div><div><span style="color:rgb(0,128,0)">       -- ^ Number of words to read</span></div><div>       -> <span style="color:rgb(0,0,255)">MemorySystem</span> <span style="color:rgb(0,16,128)">addrType</span> <span style="color:rgb(0,16,128)">wordType</span></div><div><span style="color:rgb(0,128,0)">       -- ^ The memory system from which to read</span></div><div>       -> <span style="color:rgb(0,0,255)">MemReadN</span> <span style="color:rgb(0,16,128)">addrType</span> <span style="color:rgb(0,16,128)">wordType</span></div></div></div></div><div style="color:rgb(0,0,0);font-size:13px;line-height:18px;white-space:pre"><span style="color:rgb(34,34,34);font-size:small;white-space:normal"><br></span></div><div style="color:rgb(0,0,0);font-size:13px;line-height:18px;white-space:pre"><span style="color:rgb(34,34,34);font-size:small;white-space:normal">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.</span></div><div style="color:rgb(0,0,0);font-size:13px;line-height:18px;white-space:pre"><span style="color:rgb(34,34,34);font-size:small;white-space:normal"><br></span></div><div style="color:rgb(0,0,0);font-size:13px;line-height:18px;white-space:pre"><span style="color:rgb(34,34,34);font-size:small;white-space:normal">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.</span></div><div style="color:rgb(0,0,0);font-size:13px;line-height:18px;white-space:pre"><span style="color:rgb(34,34,34);font-size:small;white-space:normal"><br></span></div><div style="color:rgb(0,0,0);font-size:13px;line-height:18px;white-space:pre"><span style="color:rgb(34,34,34);font-size:small;white-space:normal">Ideas?</span></div><div style="color:rgb(0,0,0);font-size:13px;line-height:18px;white-space:pre"><span style="color:rgb(34,34,34);font-size:small;white-space:normal"><br></span></div><div style="color:rgb(0,0,0);font-size:13px;line-height:18px;white-space:pre"><span style="color:rgb(34,34,34);font-size:small;white-space:normal"><br></span></div><div style="color:rgb(0,0,0);font-size:13px;line-height:18px;white-space:pre"><span style="color:rgb(34,34,34);font-size:small;white-space:normal">-scooter</span></div></div>