在重新启动内执行 MonadIO 操作

2024-01-07

在反应式香蕉中,我正在尝试运行reactimate :: Event (IO ()) -> Moment ()通过一些行动Arduino in hArduino封装 https://hackage.haskell.org/package/hArduino-0.9/docs/System-Hardware-Arduino.html,一个实例MonadIO。好像没有这个功能Arduino a -> IO a包装中提供。你会如何执行Arduino行动于reactimate?


我没有使用 Arduino 或 hArduino 的经验,所以对接下来的内容持保留态度。

鉴于每次都重新初始化董事会是不合理的reactimate,我认为没有一个干净的选项[*]。根本问题是落实reactimate在反应香蕉中不知道任何关于Arduinomonad,因此它添加的所有额外效果必须在此时已得到解决reactimate触发该动作(因此IO类型)。我能看到的唯一出路是推出你自己的版本withArduino跳过初始化。快速浏览一下source https://hackage.haskell.org/package/hArduino-0.9/docs/src/System-Hardware-Arduino-Comm.html#withArduino,这看起来可行,尽管非常混乱。

[*] 或者至少是一个不涉及可变状态的干净选项,如正确的答案所示。


鉴于海因里希·阿普费尔穆斯(Heinrich Apfelmus)善意地通过提出一个有趣的出路来补充这个答案,我忍不住实施了他的建议。这也归功于 gelisam,因为他的答案的框架节省了我相当多的时间。除了代码块下方的注释之外,请参阅海因里希的博客 http://apfelmus.nfshost.com/blog/2012/06/07-forklift.html有关“叉车”的额外评论。

{-# LANGUAGE GeneralizedNewtypeDeriving, ScopedTypeVariables #-}

import Control.Monad (join, (<=<), forever)
import Control.Concurrent
import Data.Word
import Text.Printf
import Text.Read (readMaybe)
import Reactive.Banana
import Reactive.Banana.Frameworks

main :: IO ()
main = do
    let inputPin  = pin 1
        outputPin = pin 2

        readInputPin = digitalRead inputPin
        copyPin = digitalWrite outputPin =<< readInputPin

    ard <- newForkLift withArduino

    (lineAddHandler, fireLine) <- newAddHandler

    let networkDescription :: forall t. Frameworks t => Moment t ()
        networkDescription = do
            eLine <- fromAddHandler lineAddHandler

            let eCopyPin = copyPin <$ filterE ("c" ==) eLine
                eReadInputPin = readInputPin <$ filterE ("i" ==) eLine

            reactimate $ (printf "Input pin is on? %s\n" . show <=< carry ard)
                <$> eReadInputPin
            reactimate $ carry ard
                <$> eCopyPin

    actuate =<< compile networkDescription

    initialised <- newQSem 0
    carry ard $ liftIO (signalQSem initialised)
    waitQSem initialised

    forever $ do
        putStrLn "Enter c to copy, i to read input pin."
        fireLine =<< getLine

-- Heinrich's forklift.

data ForkLift m = ForkLift { requests :: Chan (m ()) }

newForkLift :: MonadIO m
            => (m () -> IO ()) -> IO (ForkLift m)
newForkLift unlift = do
    channel <- newChan
    let loop = forever . join . liftIO $ readChan channel
    forkIO $ unlift loop
    return $ ForkLift channel

carry :: MonadIO m => ForkLift m -> m a -> IO a
carry forklift act = do
    ref <- newEmptyMVar
    writeChan (requests forklift) $ do
        liftIO . putMVar ref =<< act
    takeMVar ref

-- Mock-up lifted from gelisam's answer.
-- Please pretend that Arduino is abstract.

newtype Arduino a = Arduino { unArduino :: IO a }
  deriving (Functor, Applicative, Monad, MonadIO)

newtype Pin = Pin Word8

pin :: Word8 -> Pin
pin = Pin

digitalWrite :: Pin -> Bool -> Arduino ()
digitalWrite (Pin n) v = Arduino $ do
    printf "Pretend pin %d on the arduino just got turned %s.\n"
           n (if v then "on" else "off")

digitalRead :: Pin -> Arduino Bool
digitalRead p@(Pin n) = Arduino $ do
    printf "We need to pretend we read a value from pin %d.\n" n
    putStrLn "Should we return True or False?"
    line <- getLine
    case readMaybe line of
        Just v -> return v
        Nothing -> do
            putStrLn "Bad read, retrying..."
            unArduino $ digitalRead p

withArduino :: Arduino () -> IO ()
withArduino (Arduino body) = do
    putStrLn "Pretend we're initializing the arduino."
    body

Notes:

  • 叉车(这里,ard)运行一个Arduino在单独的线程中循环。carry允许我们发送Arduino命令如readInputPin and copyPin通过a在这个线程中执行Chan (Arduino ()).

  • 它只是一个名字,但无论如何它的论点newForkLift被叫unlift很好地反映了上面的讨论。

  • 通信是双向的。carry crafts MVars 使我们能够访问由Arduino命令。这使我们能够使用类似的事件eReadInputPin以完全自然的方式。

  • 各层完全分离。一方面,主循环仅触发 UI 事件,例如eLine,然后由事件网络处理。另一方面,Arduino代码仅通过叉车与事件网络和主循环进行通信。

  • 为什么我放了一个信号 https://hackage.haskell.org/package/base-4.8.1.0/docs/Control-Concurrent-QSem.html在那里?我会让你猜猜如果你把它脱下来会发生什么......

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在重新启动内执行 MonadIO 操作 的相关文章

随机推荐

  • Numpy 一次将数组与多个标量进行比较

    假设我有一个数组 a np array 1 2 3 我想将它与一些标量进行比较 这工作得很好 就像 a 2 False True False 有没有办法可以同时使用多个标量进行这样的比较 比较两个数组时的默认行为是进行元素比较 但我希望一个
  • Django如何访问抽象Base模型局部变量

    我将这个抽象基本模型定义如下 class ActivityAbstractBaseModel models Model POOR PR FAIR FA MEDIOCRE ME GOOD ENOUGH GE GOOD GO VERY GOOD
  • ODBC 不断提示输入密码

    我有一个在 Access 2003 中构建的应用程序 它使用系统 DSN ODBC 连接到 SQL Server ODBC 使用 SQL 身份验证 当应用程序启动时 系统会提示用户在数据库中进行身份验证 我在同一域中设置了另一台计算机 并安
  • 在 Hive 中获取系统日期 -1

    有什么办法可以得到current date 1在 Hive 中的意思是yesterdays date总是 并且以这种格式 20120805 我可以像这样运行查询来获取数据yesterday s date就像今天一样Aug 6th selec
  • 防止xss攻击的更好方法

    这两种方法中哪一种是更好的防止 xss 攻击的方法 保存在数据库中时的 HTMLEntities 显示 回显时的 HTMLEntities 我发现第一个更好 因为您可能会在显示时忘记添加它 两者中哪一个是更好的防止xss攻击的方法 保存在数
  • 将 Spark 数据加载到 Mongo / Memcached 中以供 Web 服务使用

    我对 Spark 非常陌生 并且有一个特定的工作流程相关问题 虽然它并不是真正与编码相关的问题 但它更像是与 Spark 功能相关的问题 我认为它在这里是合适的 如果您认为这个问题不适合 请随时将我重定向到正确的网站 所以这里是 1 我计划
  • 在没有管理员权限的情况下安装 MSBuild 15(Microsoft 构建工具)?

    有没有办法在没有管理员权限的情况下在我的计算机上本地安装 MSBuild 15 微软安装程序开启https www visualstudio com downloads https www visualstudio com download
  • 我怎样才能获得正确的付款期限?

    我觉得这更像是数学问题 我公司的员工遍布全国各地 公司的某些部门采用 奇数 工资周期 而另一些部门则采用 偶数 工资周期 我将给定支付期的开始日期称为 支付期 我需要做两件事 1 确定给定日期所属的发薪期 Something like th
  • 了解简单 C 程序生成的汇编代码

    我试图通过使用 gdb 的反汇编程序检查简单 C 程序的汇编级代码 以下是C代码 include
  • 如何为 Dagger2 提供 GoogleApiClient 依赖项?

    我已经开始使用 Dagger2 来管理依赖项 并且我试图了解如何使用 DI 来提供单例 GoogleApiClient 这样做的动机是 减少样板代码 多个 Activity 和 Fragments 需要 GoogleApiClient 提高
  • Vuejs - 无法读取未定义的属性“_withTask”

    我试图在按下按钮后将新的 html 添加到我的 div 中 使用v for 但是在我按下按钮后 我收到此错误 并且元素 文章 被添加到 div 一次 但之后它就不再起作用了 vue js 3de6 1743 TypeError 无法读取未定
  • Visual Studio 2015 RC - 无法添加虚拟目录

    我最近升级了我的机器 这意味着我必须安装 VS 2015 RC 社区 打开以前的项目 必须重新创建以前的所有虚拟目录 才发现当我尝试时收到以下错误消息 操作无法完成 只需选择 添加虚拟目录 时 输入名称和路径 然后按 Enter 键 还有其
  • Tensorflow Dataset API 在完成一个 epoch 后恢复迭代器

    我有 190 个特征和标签 我的批量大小是 20 但经过 9 次迭代tf reshape正在返回异常reshape 的输入是一个有 21 个值的张量 但请求的形状有 60 个我知道这是因为Iterator get next 如何恢复我的迭代
  • 如何使用 pandas 将列中的每个 NaN 替换为不同的随机值?

    我最近一直在玩 pandas 现在我尝试用不同的正态分布随机值替换数据框中的 NaN 值 假设我有这个没有标题的 CSV 文件 0 0 343 1 483 2 101 3 NaN 4 NaN 5 NaN 我的预期结果应该是这样的 0 0 3
  • 文本在*内*边界框内对齐

    文本框的对齐方式可以通过horizontalalignment ha and verticalalignment va 参数 例如 import matplotlib pyplot as plt fig ax plt subplots fi
  • GitLab Pipeline 无法连接到 Kubernetes

    当我执行视频显示的管道作业时 它失败并给出一条消息 错误 准备失败 连接到 Kubernetes 时出错 配置无效 未提供配置 这是故意的吗 我错过了任何配置吗 kubernetes 是为我的跑步者和我正在处理的项目配置的 但我没有看到任何
  • 使用只有很棒的字体的标记图标,没有周围的气球

    我的代码运行良好 但我只需要显示要显示的图标 而不是带有阴影的 气球 我尝试过删除 markerColor 但这只是更改为默认的蓝色标记 气球 如何只显示图标及其大小和颜色 pointToLayer function feature lat
  • 如何在iOS中使用Openssl工具解密使用AES128加密的数据

    我有很多代码片段 它们使用 AES128 加密数据 如果您提供工作实现 我将非常感激 例如这个 NSData AES128EncryptWithKey NSString key key should be 16 bytes for AES1
  • RxJS 替代 Promise.resolve?

    RxJS 中相当于什么Promise resolve 我知道我能做到Observable fromPromise Promise resolve someValue 但必须有一种更清洁的方法 可观察的 of https github com
  • 在重新启动内执行 MonadIO 操作

    在反应式香蕉中 我正在尝试运行reactimate Event IO gt Moment 通过一些行动Arduino in hArduino封装 https hackage haskell org package hArduino 0 9