使用 monad 堆栈进行依赖注入

2023-11-25

I'm 尝试不同的方法执行有时称为依赖项注入的操作。为此,我详细阐述了一个天气应用程序的简单示例,我们要在其中获取天气数据(从网络服务或硬件设备),存储天气数据(可以是数据库或简单的文件),并报告(将其打印到屏幕上,或说出天气)。这个想法是编写一个程序,使用一些fetch, store, and report函数,其实现可能会有所不同。

我已经成功地将关注点从检索、存储和报告的实现中分离出来,并使用功能 and 自由单子,但是我用 monad stacks 达成的解决方案看起来很糟糕:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module WeatherReporterMTL where

import           Control.Monad.IO.Class
import           Control.Monad.Trans.Class

type WeatherData = String

class Monad m => WeatherService m where
    fetch :: m WeatherData

class Monad m => Storage m where
    store :: WeatherData -> m ()

class Monad m => Reporter m where
    report :: WeatherData -> m ()

-- | A dummy implementation of the @WeatherService@
newtype DummyService m a = DummyService { runDummyService :: m a }
    deriving (Functor, Applicative, Monad, MonadIO)

instance MonadIO m => WeatherService (DummyService m) where
    fetch = return "won't get any warmer in December."

-- | A dummy implementation of the @Storage@
newtype DummyStorage m a = DummyStorage { runDummyStorage :: m a }
    deriving (Functor, Applicative, Monad, MonadIO, WeatherService)

-- It seems wrong that the storage has to be an instance the weather service
-- (@WeatherService@) ...

instance MonadIO m => Storage (DummyStorage m) where
    store d = liftIO $ putStrLn $ "No room left for this report: " ++ d

-- | A dummy implementation of the @Reporter@
newtype DummyReporter m a = DummyReporter { runDummyReporter :: m a }
    deriving (Functor, Applicative, Monad, MonadIO, WeatherService, Storage)

-- Ok, now this seems even worse: we're putting information about
-- how we're gonna stack our monads :/

instance MonadIO m => Reporter (DummyReporter m) where
    report d = liftIO $ putStrLn $ "Here at the MTL side " ++ d

reportWeather :: (WeatherService m, Storage m, Reporter m) => m ()
reportWeather = do
    w <- fetch
    store w
    report w

dummyWeatherReport :: IO ()
dummyWeatherReport = runDummyService $ runDummyStorage $ runDummyReporter reportWeather

在上面的代码中,两者DummyStorage and DummyReporter必须有简单的实例WeatherService,这显然是错误的。此外,这些实例取决于单子最终堆叠的顺序。有没有办法避免不同堆栈之间的信息泄漏?


也许您可以拥有需要访问 IO 和一些必要的簿记状态的“自由浮动”实现函数,而不是将实现绑定到特定的新类型,例如

data WeatherState = WeatherState -- dummy
fetch' :: (MonadState WeatherState m,MonadIO m) => m WeatherData
fetch' = undefined 
data StorageState = StorageState -- dummy
store' :: (MonadState StorageState m,MonadIO m) => WeatherData -> m ()
store' = undefined 
data ReporterState = ReporterState -- dummy
report' :: (MonadState ReporterState m,MonadIO m) => WeatherData -> m ()
report' = undefined

“注入”意味着创建一些新类型StateT携带所需的状态,然后声明实例,例如

newtype Injected a = 
    Injected { getInjected :: StateT (WeatherState,StorageState,ReportState) a } 
    deriving (Functor,Applicative,Monad)

instance WeatherService Injected where
    fetch = Injected $ zoom _1 fetch'

instance Storage Injected where
    store x = Injected $ zoom _2 $ store' x

instance Reporter Injected where
    report x = Injected $ zoom _3 $ report' x

(_1来自微透镜 and zoom from 微透镜-mtl.)

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

使用 monad 堆栈进行依赖注入 的相关文章

  • 规范化且不可变的数据模型

    Haskell如何解决 规范化不可变数据结构 问题 例如 让我们考虑一个表示前女友 男友的数据结构 data Man Man name String exes Woman data Woman Woman name String exes
  • 以下两个 lambda 函数的空间复杂度

    我正在阅读以下内容 https en wikibooks org wiki Haskell Graph reduction https en wikibooks org wiki Haskell Graph reduction 其内容如下
  • 如何在 Haskell 中安装库?

    我尝试使用控制 Monad Extra andM https hackage haskell org package extra 1 7 10 docs Control Monad Extra html import Control Mon
  • 在 Yesod 生态系统中,对某些文本进行 urlencode 的最佳方式是什么?

    我想对一些文本进行 url 编码 例如 用 20 替换每个空格等 我找到了 HTTP Network HTTP Base urlEncode 并且可以使用它 但我想知道是否还有其他通常在 Yesod 生态系统中使用的东西 不幸的是 由于 U
  • 这是依赖注入吗?这是一种不好的做法吗?

    我有一个小框架 我是这样编码的 我不确定这是否称为依赖注入 我不知道它是否像设计模式 我也不知道并且想知道是否通过 this因为 param 是一种不好的做法 看看这个 不是一个有效的示例 只是将这些代码写入浏览器中以供解释 This is
  • ASP.NET Web API 依赖注入

    我想知道是否可以在 ASP NET Web API 中进行依赖项注入 自定义构造函数 而无需使用第三方库 例如 Unity 或 StructureMap 且无需实体框架 我想要实现的是拥有一个带有构造函数的控制器 例如 public Con
  • 标准的能力

    我发现了一些使用标准的旧例子here http www serpentine com blog 2009 09 29 criterion a new benchmarking library for haskell 看起来好像早在 2009
  • 有没有一种简单的方法来为每个类创建一个记录器实例?

    我现在使用静态方法来记录 因为我发现在Android中登录非常容易 但是现在我需要为不同的类配置不同的appender 所以我对静态记录方法有一个问题 我读了Log4J 创建 Logger 实例的策略 https stackoverflow
  • Haskell / GHC - 是否有“警告不完整模式”的中缀标签/编译指示

    我正在寻找一个可以对特定的不完整模式发出警告的编译指示 它会使编译器失败并显示以下 假设的 代码 FAILIF incomplete patterns f Int gt Int f 0 0 我正在尝试使用 Arrows 编写一个 编译器 并
  • QuickCheck是否可以生成任意函数

    我试图为身份编写一个 QuickCheck 测试 f y f y 我最初的计划是编写一个返回函数和整数的任意生成器 具有签名Gen Int gt Int Int 并在prop DollerDoesNothing使用 不使用测试该功能应用程序
  • 为什么 ZipList 不是 List 的默认应用实例

    我目前正在学习 Haskell 中的应用程序 如果我没记错的话 列表有两个不同的应用实例 List and ZipList 第二个被定义为包装列表值的新类型 这ZipList应用实例对我来说似乎更直观 这可能是一个愚蠢的问题 但有具体原因吗
  • Haskell 对于 Web 应用程序来说足够成熟吗? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 在 monad 转换器类型类中使用列表 monad?

    我的目标是创建一个在 ReaderT WriterT 堆栈或 RWS 堆栈中使用列表 monad 的函数 更一般地说 如何在 mtl 类型类 例如 MonadReader MonadWriter 中使用列表 monad 我为什么要尝试这样做
  • 如何通过“cabal build”或“stack build”构建带有图标的项目

    我想构建一个带有图标的可执行文件 通过谷歌搜索 我发现这里的说明 https wiki haskell org Setting an executable icon 但它只能通过编译源文件来工作ghc 如果我想构建一个具有可执行文件的项目c
  • Data.Sequence 中的 inits 和 tails 如何工作?

    Louis Wasserman 编写了当前的实现inits and tails in Data Sequence 他表示它们非常高效 事实上 只要查看代码 我就可以看到 无论它们在做什么 它们都是以干净 自上而下的方式进行的 这往往会给惰性
  • 实体框架 4 DB 优先依赖注入?

    我更喜欢创建自己的数据库 设置索引 唯一约束等 使用 edmx 实体框架设计器 从数据库生成域模型是轻而易举的事 现在我有兴趣使用依赖注入来设置一些存储库 我查看了 StackOverflow 上的一些文章和帖子 似乎重点关注代码优先方法
  • Guice:使用@Named创建对象

    使用Guice 如果我有的话 Inject Named light Color light 我可以用 bind Color class annotatedWith Names named light toInstance new Color
  • 如何在Haskell中实现词法分析器和解析器

    我在这里得到了这段代码 它是用Haskell结构的命令式编程语言编写的程序 所以问题是 我如何为这种语言实现词法分析器和解析器 该程序被定义为一系列语句有 6 种类型 goto write stop if goto 和 int int n
  • 如何打乱列表?

    如何从一组数字 1 2 3 直到我击中x 我的计划是重新调整列表 1 2 3 并把它砍在x chopAt 3 2 3 1 2 3 chopAt 3 2 1 3 2 1 3 chopAt 3 3 1 2 3 chopAt chopAt x y
  • 我是否需要采取明确的操作来促进与持久数据结构的共享?

    我来自命令式背景 正在尝试实现一个简单的不相交集 并集查找 数据结构 以获得在 Haskell 中创建和修改 持久 数据结构的一些练习 目标是有一个简单的实现 但我也关心效率 我的问题与此相关 首先 我创建了一个按等级并集的不相交集森林实现

随机推荐

  • 如何阻止 Apache 中的特定用户代理

    我正在配置我的 Django 应用程序以通过电子邮件向我发送错误 异常 通常没有问题 但我的电子邮件托管在 Office 365 上 并且 Microsoft 似乎会自动扫描和加载电子邮件中的 URL 结果是它命中了我的 Django 应用
  • PHP 检测文件系统编码/保存具有非拉丁文件名的文件

    我需要使用 PHP 将非拉丁文件名的文件保存在文件系统上 我想让这个工作跨平台 我如何知道可以使用什么编码来写入文件 我知道许多现代文件系统都是基于 UTF 8 的 这是正确的吗 但我怀疑 Windows XP 是基于 UTF 8 的 那么
  • 为什么setContextClassLoader()方法要放在Thread上呢?

    为什么是setContextClassLoader 方法置于Thread 什么不同的线程有不同的类加载器 问题是如果我延长一个ClassLoader 加载了一些新类 到我的自定义类加载器 现在 我希望它成为上下文类加载器 所以我调用该方法T
  • AtomicInteger 等原子包类如何工作

    我读过 使用原子包类使我们能够进行线程安全 无锁编码 但我不太确定原子包类中的方法在不使用锁或任何同步关键字的情况下如何提供线程安全性 任何帮助都将不胜感激 他们使用非常低级的指令 例如比较和交换 以及来自的多种其他方法sun misc 不
  • CONNECTIVITY_ACTION 的 BroadcastReceiver 始终在intent.getExtras() 中返回 null

    我正在尝试接收来自 CONNECTIVITY ACTION 的广播消息 register BroadcastReceiver on network state changes final IntentFilter mIFNetwork ne
  • python 以什么顺序显示字典键? [复制]

    这个问题在这里已经有答案了 gt gt gt D a 1 b 2 c 3 gt gt gt D a 1 c 3 b 2 我刚刚在 Python shell 中执行了此操作 我只是想知道为什么键 c 会在键 b 之后 该顺序与它们内部的工作方
  • jQuery.validator.unobtrusive.adapters.addMinMax 往返,在 MVC3 中不起作用

    我正在使用 DataAnnotations jQuery validate 和 jquery validate unobtrusive 创建一个日期范围验证器 我已经阅读了以下内容 http bradwilson typepad com b
  • 观察类中静态变量的值?

    我有一堂课 有一个static var存储当前在线连接状态的位置 我想观察的价值ConnectionManager online通过其他课程 我想这样做KVO 但声明一个static变量为dynamic导致错误 class Connecti
  • 如何完全更改 tkinter.ttk Treeview 上的背景颜色

    我一直在尝试为我最近使用 tkinter 在 python 3 4 4 中开发的一个项目制作一个目录浏览器 我不希望背景成为默认颜色 因此我已经开始更改大多数小部件的背景 直到到达Treeview 之前我没有遇到任何麻烦 我不太擅长 ttk
  • 如何使用 CSS 轻松地将

    这个问题在这里已经有答案了 我正在尝试水平居中 div 页面上的块元素并将其设置为最小宽度 最简单的方法是什么 我想要 div 元素与页面的其余部分内联 我将尝试画一个例子 page text page text page text pag
  • JavaScript:“文档”和“HTML”之间有什么区别

    Example document click function blah and html click function blah 我将分几个部分来回答这个问题 在 JavaScript 不仅仅是 jQuery 而是所有 JavaScrip
  • 在Python脚本中检测相似文档的算法[关闭]

    很难说出这里问的是什么 这个问题模棱两可 含糊不清 不完整 过于宽泛或言辞激烈 无法以目前的形式合理回答 如需帮助澄清此问题以便重新打开 访问帮助中心 我需要编写一个模块来检测类似文档 我读过很多关于文档指纹技术等的论文 但我不知道如何编写
  • Android - 可绘制重复形状来创建图案

    我需要创建一个图案来设置为某些背景View 我希望该模式看起来像这样 我不想将任何图像导入到可绘制对象中 而是想创建自己的形状 图层列表 最终目标是有一个图案作为背景 是否可以在不导入任何外部图像的情况下实现这一目标 您可以通过创建自定义形
  • verifyError - 验证者拒绝类

    我正在开发 2 2 minSdkVersion 8 突然我收到这个错误 arbitrarily rejecting large method regs 75 count 28584 rejected Lcom Demo Loyalty Se
  • 角度材质表字母数字排序行为

    我在角度材质表中遇到问题 尽管它在技术上是正确的 但我在想是否有另一种方法可以解决这个问题 假设我有 5 个代码 F1 F2 F5 F9 F10 角度材质表升序排列顺序将是 F1 F10 F2 F5 F9 但我期待它是 F1 F2 F5 F
  • 为什么验证会违反单子定律?

    On SO解释了为什么 scalaz cats Scala 或 Arrow Kotlin 中的 Validation 不能是 monad 据我了解 这是因为他们根据应用函子对单子进行了建模 并且作为应用的验证的所需行为 收集所有无效值 与作
  • 字符串流提取整数

    为什么我无法将整数值提取到Num多变的 include
  • 如何访问注释属性中描述的字段

    是否可以访问字段值 其中字段名称在注释中描述 该注释注释类中的另一个字段 例如 Entity public class User NotBlank private String password Match field password p
  • 如何防止 FOR JSON PATH 转义查询结果?

    我正在尝试编写一个相当复杂的 SQL 查询 生成 JSON 作为结果 除了一些硬编码数组之外 一切都工作得很好 我需要在必须使用的层次结构中更深入UNION ALL创造 我生成了一个查询 在此处显示了我的问题 不需要数据 我在 Azure
  • 使用 monad 堆栈进行依赖注入

    I m 尝试不同的方法执行有时称为依赖项注入的操作 为此 我详细阐述了一个天气应用程序的简单示例 我们要在其中获取天气数据 从网络服务或硬件设备 存储天气数据 可以是数据库或简单的文件 并报告 将其打印到屏幕上 或说出天气 这个想法是编写一