加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – Reader monad有什么好处?

发布时间:2020-12-16 18:42:58 所属栏目:安全 来源:网络整理
导读:我读过一个关于Reader monad的 blog post. 帖子真的很棒,并详细解释了这个主题,但我不明白为什么我应该在这种情况下使用Reader monad. 帖子说:假设有一个函数查询:String =连接=结果集 def query(sql:String) = conn:Connection = conn.createStatement.ex
我读过一个关于Reader monad的 blog post.

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

帖子说:假设有一个函数查询:String =>连接=>结果集

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代替:

class Reader[E,A](run: E => A) {

  def map[B](f: A => B):Reader[E,B] =
    new Reader(е=> f(run(е)))

  def flatMap[B](f:A => Reader[E,B]): Reader[E,B] =
    new Reader(е => f(run(е)).run(е))  
}

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

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

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

更新:修正了def查询中的拼写错误:= should be =>
此注释仅存在,因为SO坚持编辑必须至少6个字符长.所以我们走了.

解决方法

最重要的原因是读者monad允许您在组合上构建复杂的计算.请考虑非读者示例中的以下行:

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

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

通常这很好 – 显然,定义和使用局部变量没有任何问题(至少在val意义上).但是,有时候,通过独立的,可组合的部分构建计算会更方便(或者出于其他原因),并且读者monad可以帮助解决这个问题.

在第二个示例中考虑查询(“SELECT COUNT(*)FROM Foo”).假设我们知道什么是查询,这是一个完全自包含的表达式 – 没有像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.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读