You need to sequence your Monad
computations. I'll write it generally and simply then specifically for your situation.
The problem you have is you have a function f :: A -> IO B
and another function g :: B -> IO C
which feel like they ought to be combinable, but aren't quite---the second function needs a plain B
, not the IO B
that the first one returns.
This is exactly where the power of Monad
s comes into play. Knowing that IO
is a monad, we can use a function like (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
to combine these Monad
ic functions. In fact, already, f >=> g :: A -> IO C
like we require.
We can also use do
notation which would require us to "bind" the return type of f
and then apply that to g
to get the output.
\a -> do b <- f a
g b
which gives us a function of type A -> IO C
again. In fact, this do
notation is basically the definition of (>=>)
.
So how does this apply in your particular circumstance? Well,
let mybrick = openSerial "/dev/tty.NXT-DevB" defaultSerialSettings
gives you a mybrick :: IO SerialPort
value. In order to use send :: SerialPort -> ByteString -> IO Int
we need to "unwrap" mybrick
from the IO
Monad
. So we can use do
notation
do sp <- mybrick
send sp message
Or, to make everything neater, we can just run the entire computation using do
notation
do mybrick <- openSerial "/dev/tty.NXT-DevB" defaultSerialSettings
send mybrick message