Scala IO monad:有什么意义?
我最近看过一个视频,你怎么可以想出IO monad,这个演讲是在scala。实际上我想知道有什么功能返回IO [A]。包含在IO对象中的lambda表达式是突变是什么,在某些点上它们必须被观察到的更改更高,我的意思是执行,以便发生某些事情。你不是只是把树上的问题提高到别的地方吗?
我可以看到的唯一好处是允许进行懒惰评估,因为如果不调用unsafePerformIO操作,则不会发生任何副作用。此外,我猜其他程序的部分可以使用/共享代码,并在需要发生副作用时进行解析。 我想知道这是否全部?可测试性有哪些优点?我假设不像你会观察到这种否定的影响。如果您使用traits / interfaces,则可以控制依赖关系,但不影响这些依赖关系的效果。 我将代码中的以下示例放在一起。 case class IO[+A](val ra: () => A){ def unsafePerformIO() : A = ra(); def map[B](f: A => B) : IO[B] = IO[B]( () => f(unsafePerformIO())) def flatMap[B](f: A => IO[B]) : IO[B] = { IO( () => f(ra()).unsafePerformIO()) } } case class Person(age: Int,name: String) object Runner { def getOlderPerson(p1: Person,p2:Person) : Person = if(p1.age > p2.age) p1 else p2 def printOlder(p1: Person,p2: Person): IO[Unit] = { IO( () => println(getOlderPerson(p1,p2)) ).map( x => println("Next") ) } def printPerson(p:Person) = IO(() => { println(p) p }) def main(args: Array[String]): Unit = { val result = printPerson(Person(31,"Blair")).flatMap(a => printPerson(Person(23,"Tom")) .flatMap(b => printOlder(a,b))) result.unsafePerformIO() } } 你可以看到效果如何推迟到主,我猜是很酷。从视频中感受到这一点后,我想出了这一点。 我的实现是否正确,我的理解是否正确。 我也想知道是否应该与ValidationMonad结合使用,如ValidationMonad [IO [Person]]所以我们可以在发生异常时短路?想想 布莱尔 解决方法
对于记录其是否具有副作用的功能的类型签名是有价值的。您的IO实现具有价值,因为它实现了这一点。它使您的代码更好地记录在案;并且如果您重写代码以尽可能多地分离逻辑,这些逻辑涉及到不是逻辑的IO,那么使非IO涉及的函数更可组合并且更可测试。您可以在没有显式IO类型的情况下进行相同的重构;但使用显式类型意味着编译器可以帮助您进行分离。
但这只是开始。在您的问题的代码中,IO操作被编码为lambdas,因此是不透明的;除了运行IO操作之外,您可以使用IO操作无关,并且运行时的效果是硬编码的。 这不是实现IO monad的唯一可能的方法。 例如,我可能会使我的IO操作case类扩展一个共同的特征。那么我可以这样写一个运行函数的测试,看看它是否返回正确的IO操作。 在那些代表不同种类的IO操作的类中,我可能不会包含在运行时该操作执行的硬编码实现。相反,我可以使用类型类型来解耦。这将允许在IO操作的不同实现中进行交换。例如,我可能有一组与生产数据库通信的实现,另一组与模拟内存数据库进行交互以进行测试。 在Bjarnason& S的第13章(“外部效果和I / O”)中对这些问题有很好的对待。 Chiusano的“Scala中的功能编程”一书。特别参见13.2.2“简单IO类型的优点和缺点”。 更新(2015年12月):重新“在IO操作的不同实现中进行交换”,这些日子越来越多的人对这种事情使用“自由monad”参见例如John De Goes的博文“A Modern Architecture for FP”。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |