IO monads, stream handles, and type inference

:t pause pause :: Double ->
In the thread "Precise timing https://groups.google.com/forum/#!topic/haskell-cafe/sf8W4KBTYqQ", in response to something ugly I was doing, Rohan Drape provided the following code: import Control.Concurrent import Control.Monad import System.IO import Sound.OSC main = withMax $ mapM_ note (cycle [1,1,2]) withMax = withTransport (openUDP "127.0.0.1" 9000) sin0 param val = sendMessage (Message "sin0" [string param,float val]) pause = liftIO . pauseThread . (* 0.1) note n = do sin0 "frq" 300 sin0 "amp" 1 pause n sin0 "amp" 0 pause n For days I have monkeyed with it, and studied the libraries it imports, and I remain sorely confused. *How can the "a" in "IO a" be a handle?* Here are two type signatures: openUDP :: String -> Int -> IO UDP withTransport :: Transport t => IO t -> Connection t a -> IO a Rohan's code makes clear that openUDP creates a handle representing the UDP connection. openUDP's type signature indicates that its output is an "IO UDP". How can I reconcile those two facts? When I read about the IO type, all sources seem to indicate that "IO a" represents a value of type "a" wrapped in an IO context. For instance, when putting Strings to the screen, one passes around "IO String" values. Until this OSC library, I had never seen the "a" in "IO a" represent a pipe; it had always represented data to be passed *through* a pipe. *Why the long signature?* When I ask for it, GHC provides the following additional type signatures: transformers-0.3.0.0:Control.Monad.Trans.Reader.ReaderT UDP IO () What's up with that? *What type is note? (and related questions)* GHCI goes on: > :t sin0 sin0 :: (SendOSC m, Real n) => String -> n -> m () > :t note note :: Double -> transformers-0.3.0.0:Control.Monad.Trans.Reader.ReaderT UDP IO () note calls both sin0 and pause. It appears that note's type signature takes pause, but not sin0, into account, but I must be wrong about that. sin0 returns a SendOSC. pause applies liftIO to pauseThread. The result must be a SendOSC too, because sin0 and pause are both called in the same do loop. SendOSC implements these three classes: (Monad (ReaderT t io), Transport t, MonadIO io) => SendOSC (ReaderT t io) Is the liftIO that pause applies to pauseThread, then, the "default" liftIO defined in the MonadIO library? *How to read the "instances" portion of Hackage documentation?* In the Hackage documentation https://hackage.haskell.org/package/hosc-0.13/docs/Sound-OSC-Transport-Monad... for the SendOSC type, how should I be reading this line? (Monad (ReaderT t io), Transport t, MonadIO io) => SendOSC (ReaderT t io) I understand the middle two clauses: that io should be of type MonadIO, and t should be of type Transport. The outer two clauses, though, I don't know how to interpret. (I looked at the code https://hackage.haskell.org/package/hosc-0.13/docs/src/Sound-OSC-Transport-M... and saw nothing that clearly corresponded to that line in the documentation.)

On Mon, Nov 10, 2014 at 10:09 PM, Jeffrey Brown
Until this OSC library, I had never seen the "a" in "IO a" represent a pipe; it had always represented data to be passed *through* a pipe.
http://lambda.haskell.org/platform/doc/current/ghc-doc/libraries/haskell2010... produces an IO Handle. File I/O is often done with lazy I/O, which hides the Handle in the woodwork, but nothing stops you from using Handle-based I/O.
:t pause pause :: Double ->
*Why the long signature?* When I ask for it, GHC provides the following additional type signatures: transformers-0.3.0.0:Control.Monad.Trans.Reader.ReaderT UDP IO () What's up with that?
You don't have the module that defines the type ReaderT in scope, so it dug out where the module you *do* have in scope got it from. And it gave full details, because conceivably you could have multiple versions of the transformers library installed --- although that usually leads to a lot of confusion (which ghc is trying to avoid here by giving the full pedigree). BTW, I am going to guess, given that you later show a SendOSC that is a ReaderT UDP IO a, that SendOSC is a `type` (type alias) and not a `data` (a fully-fledged data type) or `newtype` (a wrapper for another type). That may answer your later questions: ghc will sometimes show the alias name and sometimes the type it expands to. -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

*How to read the "instances" portion of Hackage documentation?*
is there some reason to use hosc-0.13? the hackage documentation for 0.13 is very obscure on this point & for complicated reasons not much to do with hosc
I understand the middle two clauses: that io should be of type MonadIO, and t should be of type Transport.
hosc-0.15 says only "(Transport t, MonadIO io) => SendOSC (ReaderT t io)" so you may understand all there is to understand? best, rd

SendOSC is a type class and not a data type (or type synonym or newtype).
2014-11-11 5:23 GMT+01:00 Rohan Drape
*How to read the "instances" portion of Hackage documentation?*
is there some reason to use hosc-0.13?
the hackage documentation for 0.13 is very obscure on this point
& for complicated reasons not much to do with hosc
I understand the middle two clauses: that io should be of type MonadIO, and t should be of type Transport.
hosc-0.15 says only "(Transport t, MonadIO io) => SendOSC (ReaderT t io)"
so you may understand all there is to understand?
best, rd
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
participants (4)
-
Brandon Allbery
-
Felix Kunzmann
-
Jeffrey Brown
-
Rohan Drape