我正在尝试使用 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
最佳答案
您需要对您的 Monad
计算进行排序。我会根据您的情况写得笼统、简单。
你遇到的问题是你有一个函数 f::A -> IO B
和另一个函数 g::B -> IO C
感觉它们应该可以组合,但不完全是——第二个函数需要一个plain B
,而不是第一个函数返回的IO B
.
这正是 Monad 的力量发挥作用的地方。知道 IO
是一个 monad,我们可以使用像 (>=>)::Monad m => (a -> m b) -> (b -> m c) -> 这样的函数a -> m c
组合这些 Monad 函数。事实上,f >=> g::A -> IO C
已经像我们所要求的那样了。
我们还可以使用 do
表示法,这需要我们“绑定(bind)”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
,我们需要从 IO
Monad 中“解开”
。所以我们可以使用 mybrick
do
表示法
do sp <- mybrick
send sp message
或者,为了让一切变得更简洁,我们可以使用 do
表示法运行整个计算
do mybrick <- openSerial "/dev/tty.NXT-DevB" defaultSerialSettings
send mybrick message
关于haskell - 与 Haskell 交互使用串行端口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16246277/