gpt4 book ai didi

haskell - Haskell 能否区分不同类型的 IO

转载 作者:行者123 更新时间:2023-12-04 14:27:42 24 4
gpt4 key购买 nike

免责声明:我对 Haskell 的无知几乎是完美的。对不起,如果这真的很基本,但我找不到答案,甚至找不到这样的问题。另外我的英文也不是很好。

据我所知,如果我在系统中有一个函数以某种方式与文件系统交互,这个函数必须使用 IO monad,并且类型会像 IO ()
在我(仅面向业务的)经验中,系统通常与文件系统交互以读取/写入包含业务数据的文件,以及记录日志。

而在商业应用中,日志无处不在。因此,如果我在 Haskell 中编写一个系统(我很长一段时间不会这样做),几乎每个函数都会使用 IO monad。

这是常见的做法还是以某种方式记录不需要IO()?或者 Haskell 业务应用程序不会记录那么多?

另外,其他类型的 I/O 怎么样?如果我需要从函数访问数据库或 Web 服务,该函数也使用 IO monad 还是 Haskell 也有 WS 和 DB monad?我几乎可以肯定只有一个 IO monad ......从我的角度来看,能够知道类型的 IO 看起来很棒,但我确定我的观点不是一个客观的衡量标准用处...

最佳答案

组织 Haskell 程序的一种典型方法是构建一个特定于应用程序的 monad,用于管理应用程序域所需的效果。这可以通过在我们所谓的“monad 转换器堆栈”中分层所需的功能来完成。如果 IO 在应用程序中无处不在,那么 IO 可以具体指定为堆栈的基础(这是它唯一可以容纳的地方,因为它是唯一不能被用户级代码解构的 monad),但是基础 monad 通常可以保持抽象,这意味着您可以使用非 IO monad 将其实例化以进行测试。

更具体地说,monad 转换器堆栈通常使用一组称为 Reader、Writer 和 State 的标准转换器构建。每个都提供了一个不同的“效果”,通过用该 monad 编写的代码隐式线程化。出于日志记录的目的,经常使用 Writer monad(以其转换器形式,WriterT);它本质上是您提供的 Monoid,它根据对其 tell 的调用建立一些输出。方法。如果你实现了基于tell的日志功能,那么你的应用程序 monad 中的任何函数都可以有一条日志消息 mappend编辑到日志输出。 Reader 功能通常用于通过 ask 提供一组固定的环境参数。方法;状态比较明显;它通过您的应用程序线程一些可转换的数据类型,并允许您的应用程序通过 get 转换它。和 put方法。其他 monad 转换器也由库提供;可以为您的应用程序提供类似异常的功能,ListT 可以通过 List monad 等提供非确定性。

使用这样的转换器堆栈,您通常希望将其限制在程序的“应用程序逻辑”层中,这样您的应用程序 monad 中就不需要任何不需要效果的函数。常规模块化编程实践适用;保持您的抽象松散耦合和高度内聚,并通过普通的纯函数在其中提供功能,以便应用程序逻辑可以在高级抽象上对它们进行操作。例如,如果您的业务逻辑中有一个 Person 的概念,您将在一个对您的应用程序 monad 一无所知的 Person 模块中实现有关 Person 的数据和函数。只需使其可能失败的函数返回一个具有足够信息的值来创建日志条目;当您的应用程序逻辑使用这些函数操作 Person 值时,它可以对结果进行模式匹配,或者如果您需要组合多个可能失败的函数,则它可以在运行中的 EachT monad 中工作。然后,您可以在应用程序层中使用基于 Writer 的日志记录功能。

每个 Haskell 程序的顶层总是在 IO monad 中。如果您已经将堆栈相对于其基础 Monad 抽象化,或者只是将其完全纯粹化,那么您将需要一个小的顶层来提供您的应用程序所需的 IO 功能。如果您的应用程序 monad 是交互式的,您可以一次运行一个步骤,在这种情况下,您可以解压缩 Writer 以获取日志条目以及有关应用程序逻辑请求的其他 IO 操作的信息。结果可以通过 Reader 或 State 层反馈到应用程序环境中。如果您的应用程序只是一个批处理器,您可能只通过 IO 操作的结果提供必要的输入,运行应用程序 monad,然后通过 IO 从 Writer 转储日志。

所有这一切的目的是为了说明 monad 和 monad 转换器允许您以非常干净的方式分离现实世界应用程序的各个部分,以便您可以在大多数地方充分利用纯粹、简单的函数进行数据转换,并留下您的代码非常干净和可测试。您可以在一个小的“运行时支持”层中隔离 IO 操作,在围绕(可能是纯的)monad 转换器堆栈构建的类似但更大的层中隔离特定于应用程序的逻辑,以及在一组不依赖的模块中进行业务数据操作使用它们的应用程序逻辑的任何功能。这使您可以在以后轻松地将这些模块重新用于类似域中的应用程序。

在 Haskell 中掌握程序结构的窍门需要练习(就像在任何语言中一样),但我想你会发现在阅读了一些 Haskell 应用程序并编写了一些你自己的应用程序后,它提供的功能允许你构建非常结构良好的应用程序,非常容易扩展和重构。祝你的努力好运!

关于haskell - Haskell 能否区分不同类型的 IO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24700714/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com