[Haskell-cafe] Generalizing IO
Gregory Crosswhite
gcross at phys.washington.edu
Tue Oct 6 03:36:43 EDT 2009
It isn't clear what it is that you are trying to generalize the code
to do. If you are trying to generalize it to work with an arbitrary
input/output stream of lines, then unless you are doing arbitrary I/O
it seems to me that all of these instance declarations are overkill.
All that you need is to know how to get a line from the stream, and
how to send a line.
Assuming that this is the case, you have a couple of options. If you
are only going to write to the stream within runCmd, then I'd just
pass in the line writing function as an extra argument:
type PDState = StateT PD
loop :: (m String) -> (String -> m ()) -> PDState m a
loop fetchLine sendLine = forever $ lift fetchLine >>= runCmd (lift
sendLine)
runCmd :: (String -> PDState m ()) -> PDstate m ()
runCmd sendLine cmd =
case cmd of
"Inc" -> increment
"PrintCount" -> getCount >>= sendLine . show
"PrintList" -> getList >>= sendLine . show
...
If you forsee doing reading and writing at other points in your code,
you could use the RWS monad to supply your code not only with a state
but also with an environment with the reading and writing functions:
data StreamFunctions m = StreamFunctions
{ streamLineFetcher :: m String
, streamLineSender :: String -> m ()
}
fetchLineFromStream = lift $ asks streamLineFetcher
sendLineDownStream cmd = lift (asks streamLineSender >>= return . ($
cmd))
data PDMonad = RWST (StreamFunctions m) () PD m
main = evalRWST loop (StreamFunctions ...) (PD { pdCount = 0, pdList =
[] })
loop :: PDMonad m ()
loop = forever $ fetchLineFromStream >>= runCmd
runCmd :: String -> PDMonad m ()
runCmd "Inc" = increment
runCmd "PrintCount" = getCount >>= sendLineDownStream
runCmd "PrintList" = getList >>= sendLineDownStream
Note that we didn't have to put any additional constraints on the
monad type variable "m", because other than the fact that we can get a
line and send a line within it we don't otherwise care what it is. If
you want to do other arbitrary I/O within this framework, though, then
you will need to add a "MonadIO m" constraint.
Cheers,
Greg
On Oct 5, 2009, at 8:54 PM, Floptical Logic wrote:
>> Instead of specifying the monad implementation, specify the
>> interface.
>> That is, you are using state operations (from MonadState) and IO
>> operations (from MonadIO). Try removing all the type signatures that
>> mention PDState and see what you get.
>>
>> E.g., loop :: (MonadState PD m, MonadIO m) => m a
>
> If I were to make an instance of MonadIO be a parameter to StateT and
> I wanted to use the Net monad (from Roll your own IRC bot on the wiki)
> with it, I would need to make Net an instance of MonadIO. What would
> this instance look like?
>
> I think the loop function is the least of my worries. I am more
> concerned about the runCmd function. What would go in place of print
> in runCmd?
>
> Thanks
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
More information about the Haskell-Cafe
mailing list