scala – Reader monad有什么好处?
我读过一个关于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) 好的,我知道我不需要通过调用明确地连接线程.所以呢 ? 更新:修正了def查询中的拼写错误:= should be => 解决方法
最重要的原因是读者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. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |