简体   繁体   English

像Eithers这样的错误处理单子如何实现参照透明?

[英]How do error handling monads like Eithers achieve referential transparency?

From reading about FP, my understanding of the benefits of removing side-effects is that if all our functions are pure/have referential transparency (something that can only be achieved without side-effects), then our functions are easier to test, debug, reuse, and are more modular. 通过阅读有关FP的知识,我对消除副作用的好处的理解是,如果我们所有的功能都是纯函数/具有参照透明性(只有在没有副作用的情况下才能实现),那么我们的函数更易于测试,调试,重用,并且更具模块化。

Since exceptions are a form of side-effect, we need to avoid throwing exceptions. 由于异常是一种副作用,因此我们需要避免引发异常。 Obviously we still need to be able to terminate processes when something goes wrong so FP uses monads to achieve both referential transparency and the ability to handle exceptions. 显然,当出现问题时,我们仍然需要能够终止进程,因此FP使用monad来实现引用透明性和处理异常的能力。

What I'm confused about is how exactly monads achieve this. 我感到困惑的是单子如何实现这一目标。 Suppose I have this code using scalaz 假设我有使用scalaz的代码

def couldThrowException: Exception \/ Boolean = ??
val f  = couldThrowException()
val g = couldThrowException()

Since couldThrowException may return an exception, there is no gaurantee that f and g will be the same. 由于couldThrowException可能返回异常,因此没有保证fg相同。 f could be \\/-(true) and g be a -\\/(NullPointerException) . f可以是\\/-(true)g-\\/(NullPointerException) Since couldThrowException can return different values with the same input, it is not a pure function. 由于couldThrowException可以使用相同的输入返回不同的值,所以它不是一个纯函数。 Wasn't the point of using monads to keep our functions pure? 使用monad来保持函数纯净不是很重要吗?

f() and g() should evaluate to the same value, given the same input. 在给定相同输入的情况下, f()g()计算结果相同。

In pure FP a function with no arguments must necessarily evaluate to the same result every time it's called. 在纯FP中,没有参数的函数每次调用时都必须求出相同的结果。 So it's not pure FP if your couldThrowException sometimes returns \\/-(true) and sometimes -\\/(NullPointerException) . 因此,如果您的couldThrowException有时返回\\/-(true)并有时返回-\\/(NullPointerException)那么这并不是纯粹的FP。

It makes more sense to return an Either if couldThrowException takes a parameter. 如果couldThrowException带有参数,则返回Either更有意义。 If it's a pure function, it will have referential transparency, so some inputs will always result in \\/-(true) and some inputs will always result in -\\/(NullPointerException) . 如果它是纯函数,它将具有引用透明性,因此某些输入将始终导致\\/-(true)而某些输入将始终导致-\\/(NullPointerException)

In Scala you may well be using a function that is not pure, and not referentially transparent. 在Scala中,您很可能使用的函数不是纯函数, 也不是参照透明函数。 Perhaps it's a Java class. 也许这是一个Java类。 Perhaps it's using a part of Scala that's not pure. 也许它使用的是Scala的一部分,但并不纯净。

But I guess you're interested in bridging between the pure FP world and impure libraries. 但是我想您对在纯FP世界和不纯图书馆之间架起桥梁很感兴趣。 A classic example of this is IO. 一个典型的例子是IO。 println could fail for all kinds of reasons - permissions, filesystem full, etc. println可能由于各种原因而失败-权限,文件系统已满等。

The classic way to handle this in FP is to use an IO function that takes a "world" state as an input parameter, and returns both the result of the IO call, and the new "world" state. 在FP中处理此问题的经典方法是使用IO函数,该函数以“世界”状态作为输入参数,并返回IO调用的结果和新的“世界”状态。 The state can be a "fake" value backed by library code in an impure language, but what it means is that each time you call the function, you're passing a different state, so it's referentially transparent. 状态可以是由不纯语言的库代码支持的“伪”值,但这意味着每次调用该函数时,您要传递一个不同的状态,因此它是参照透明的。

Often, a monad is used to encapsulate the "world". 通常,一个monad用于封装“世界”。

You can find out a lot about this approach by reading about Haskell's IO monad. 通过阅读Haskell的IO monad,您可以找到有关此方法的很多信息。

Core Scala IO isn't wholly pure, so println might throw and exception, and hence, as you've spotted, isn't fully referentially transparent. Core Scala IO并非完全纯净,因此println可能会抛出异常,因此,正如您所发现的那样,它并不是完全参照透明的。 Scalaz provides an IO monad similar to Haskell's. Scalaz提供类似于Haskell的IO monad。

One thing to note, because it trips up a lot of beginners: there's nothing about the "World" approach that requires a monad, and IO isn't easiest the monad to look at when first learning what a monad is and why they're useful. 需要注意的一件事,因为它吸引了许多初学者:“世界”方法并不需要单子,而IO并不是最容易在第一次学习单子是什么以及为什么要学习单子时要看的单子。有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM