与Haskell交互使用串口

iha*_*ter 2 haskell serial-port nxt

我想通过串口使用Haskell的交互模式乐高NXT发送消息,但我无法弄清楚如何使用的SerialPort正常功能.

我有一条消息,应该在类型的NXT上播放音调 ByteString

> let message = pack ([6, 0 ,0, 3, 224, 1, 208, 7]::[Word8])
Run Code Online (Sandbox Code Playgroud)

我可以使用打开串口openSerial.

openSerial :: FilePath -> SerialPortSettings -> IO SerialPort
> let mybrick = openSerial "/dev/tty.NXT-DevB" defaultSerialSettings
Run Code Online (Sandbox Code Playgroud)

但后来我卡住了.我该如何使用该send功能?

send :: SerialPort -> B.ByteString -> IO Int
> send mybrick message
Run Code Online (Sandbox Code Playgroud)

这给我以下错误信息.

<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
Run Code Online (Sandbox Code Playgroud)

J. *_*son 7

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


你遇到的问题是你有一个功能f :: A -> IO B和另一个功能g :: B -> IO C,他们觉得它们应该是可以组合的,但并不完全---第二个功能需要一个简单的 B,而不是IO B第一个返回的功能.

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

我们还可以使用do表示法,它要求我们"绑定"返回类型,f然后应用它g来获取输出.

\a -> do b <- f a
         g b
Run Code Online (Sandbox Code Playgroud)

这给了我们一个类型的功能A -> IO C.实际上,这种do符号基本上是定义的(>=>).


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

let mybrick = openSerial "/dev/tty.NXT-DevB" defaultSerialSettings
Run Code Online (Sandbox Code Playgroud)

给你一个mybrick :: IO SerialPort价值.为了使用send :: SerialPort -> ByteString -> IO Int,我们需要"解开" mybrickIO Monad.所以我们可以使用do符号

do sp <- mybrick
   send sp message
Run Code Online (Sandbox Code Playgroud)

或者,为了使一切更整洁,我们可以使用do符号运行整个计算

do mybrick <- openSerial "/dev/tty.NXT-DevB" defaultSerialSettings
   send mybrick message
Run Code Online (Sandbox Code Playgroud)