gpt4 book ai didi

scala - Reader monad 有什么好处?

转载 作者:行者123 更新时间:2023-12-04 13:39:39 26 4
gpt4 key购买 nike

我读过 blog post关于 Reader单子(monad)。

这篇文章真的很棒,并详细解释了这个主题,但我不明白为什么我应该使用 Reader monad 在这种情况下。

帖子说:假设有一个函数query: String => Connection => ResultSet
def query(sql:String) = conn:Connection => conn.createStatement.executeQuery(sql)

我们可以运行一些查询,如下所示:

def doSomeQueries(conn: Connection) = {
val rs1 = query("SELECT COUNT(*) FROM Foo")(conn)
val rs2 = query("SELECT COUNT(*) FROM Bar")(conn)
rs1.getInt(1) + rs2.getInt(1)
}


到目前为止一切顺利,但帖子建议使用 Reader单子(monad)代替:

类阅读器[E,A](运行:E => A){

def map[B](f: A => B):Reader[E, B] =
新阅读器(е=> f(运行(е)))

def flatMap[B](f:A => Reader[E, B]): Reader[E, B] =
新阅读器(е => f(run(е)).run(е))
}

val query(sql:String): Reader[Connection, ResultSet] =
新读者(conn => conn.createStatement.executeQuery(sql))

def doSomeQueries(conn: Connection) = for {
rs1 <- query("SELECT COUNT(*) FROM Foo")
rs2 <- query("SELECT COUNT(*) FROM Bar")
产生 rs1.getInt(1) + rs2.getInt(1)

好的,我知道我不需要线程 connection通过明确的调用。所以呢 ?
为什么使用 Reader 的解决方案monad 比前一个好?

更新:修正了 def 查询中的错字:= 应该是 =>
此评论仅存在,因为 SO 坚持编辑必须至少有 6 个字符长。所以我们开始吧。

最佳答案

最重要的原因是 reader monad 允许您以组合方式构建复杂的计算。考虑您的非读者示例中的以下行:

val rs1 = query("SELECT COUNT(*) FROM Foo")(conn)

我们传入 conn 的事实手动意味着这条线本身并没有真正的意义——它只能在 doSomeQueries 的上下文中理解和推理。给我们 conn 的方法.

通常这很好——定义和使用局部变量显然没有错(至少在 val 意义上)。但是,有时,从独立的、可组合的部分构建计算更方便(或出于其他原因需要),而 reader monad 可以帮助解决这个问题。

考虑 query("SELECT COUNT(*) FROM Foo")在你的第二个例子中。假设我们知道 query也就是说,这是一个完全独立的表达式——没有像 conn 这样的变量。这需要受到一些封闭范围的约束。这意味着您可以更自信地重用和重构,并且在推理时您的头脑中没有太多东西要记住。

同样,这从来都不是必需的——这主要是风格问题。如果您决定试一试(我建议您这样做),您可能很快就会形成偏好和直觉,了解哪些地方可以让您的代码更易理解,哪些地方不能。

另一个优点是您可以使用 ReaderT 组合不同类型的“效果”。 (或通过将 Reader 添加到其他堆栈中)。不过,这组问题可能值得自己提问和回答。

最后一点:你可能想要你的 doSomeQueries看起来像这样:
def doSomeQueries: Reader[Connection, Int] = for {
rs1 <- query("SELECT COUNT(*) FROM Foo")
rs2 <- query("SELECT COUNT(*) FROM Bar")
} yield rs1.getInt(1) + rs2.getInt(1)

或者,如果这真的是行尾:
def doSomeQueries(conn: Connection) = (
for {
rs1 <- query("SELECT COUNT(*) FROM Foo")
rs2 <- query("SELECT COUNT(*) FROM Bar")
} yield rs1.getInt(1) + rs2.getInt(1)
).run(conn)

在您当前的版本中,您实际上并没有使用 conn .

关于scala - Reader monad 有什么好处?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22270925/

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