与Haskell交互使用串口

时间:2013-04-26 22:43:22

标签: haskell serial-port nxt

我正在尝试使用Haskell的交互模式通过串口向Lego NXT发送消息,但我无法弄清楚如何正确使用serialport函数。

我有一条消息应该在NXT上播放ByteString

类型的音调
> let message = pack ([6, 0 ,0, 3, 224, 1, 208, 7]::[Word8])

我可以使用openSerial打开串口。

openSerial :: FilePath -> SerialPortSettings -> IO SerialPort
> let mybrick = openSerial "/dev/tty.NXT-DevB" defaultSerialSettings

但后来我陷入困境。我该如何使用send功能?

send :: SerialPort -> B.ByteString -> IO Int
> send mybrick message

这给出了以下错误消息。

<interactive>:31:6:
    Couldn't match expected type `SerialPort'
                with actual type `IO SerialPort'
    In the first argument of `send', namely `mybrick'
    In the expression: send mybrick message
    In an equation for `it': it = send mybrick message

2 个答案:

答案 0 :(得分:7)

您需要序列您的Monad计算。我会写一般的,然后专门针对你的情况。


你遇到的问题是你有一个函数f :: A -> IO B和另一个函数g :: B -> IO C,它们觉得它们应该是可以组合的,但不是很完美---第二个函数需要一个普通 B,而不是第一个返回的IO B

这正是Monad s的力量发挥作用的地方。知道IO是monad,我们可以使用像(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c这样的函数来组合这些Monad ic函数。事实上,已经f >=> g :: A -> IO C就像我们要求的那样。

我们还可以使用do表示法,要求我们“绑定”f的返回类型,然后将其应用于g以获取输出。

\a -> do b <- f a
         g b

再次为我们提供了A -> IO C类型的函数。实际上,这个do符号基本上是(>=>)的定义。


那么这在您的特定情况下如何适用?好吧,

let mybrick = openSerial "/dev/tty.NXT-DevB" defaultSerialSettings

为您提供mybrick :: IO SerialPort值。要使用send :: SerialPort -> ByteString -> IO Int,我们需要从mybrick IO“展开”Monad。所以我们可以使用do符号

do sp <- mybrick
   send sp message

或者,为了使所有内容更整洁,我们可以使用do表示法运行整个计算

do mybrick <- openSerial "/dev/tty.NXT-DevB" defaultSerialSettings
   send mybrick message

答案 1 :(得分:2)

openSerial path settings是一个IO动作,它产生一个串行端口。要访问串行端口,必须在IO monad中执行该操作。您的main看起来像这样:

main = do 
    mybrick <- openSerial "/dev/tty.NXT-DevB" defaultSerialSettings
    let message = pack ([0, 3, 224, 1, 208, 7] :: [Word8])
    send mybrick message

不同之处在于,let绑定只会为等号后面的内容创建一个新名称。在这种情况下,这会导致mybrick类型为IO SerialPort,就像错误消息所示。