android 函数式编程_Android开发人员的函数式编程-第4部分

android 函数式编程

by Anup Cowkur

通过安纳普·考库(Anup Cowkur)

Android开发人员的函数式编程-第4部分 (Functional Programming for Android Developers — Part 4)

In the last post, we learned about higher order functions and closures. In this one, we’ll talk about functional error handling.

在上一篇文章中,我们了解了高阶函数闭包 。 在这一篇中,我们将讨论功能错误处理。

If you haven’t read part 3, please read it here.

如果您尚未阅读第3部分,请在此处阅读。

功能错误处理 (Functional error handling)

If you’ve been following this series so far, you might have noticed a recurring theme in FP: Everything is a computation or a value.

如果到目前为止您一直在关注本系列,您可能已经注意到FP中一个重复出现的主题: 一切都是计算或值。

We create functions which can optionally take some values. They then perform some useful computation and return other values.

我们创建的函数可以选择取一些值。 然后,它们执行一些有用的计算并返回其他值。

In most OOP programming, we treat errors as exceptions — things that are not part of the computation result. The big difference in FP is that we model errors just like any other value. Errors are a natural part of computation, not extraneous agents of evil that showed up out of nowhere.

在大多数OOP编程中,我们将错误视为异常,即不属于计算结果的内容。 FP的最大区别在于,我们像其他任何值一样对错误进行建模。 错误是计算的自然组成部分,而不是无处出现的无关紧要的恶魔。

Here’s an example of some typical error handling in OOP:

这是OOP中一些典型错误处理的示例:

try {  result = readFromDB()} catch (e: Exception) {  result = null}

The result of the function readFromDb is an error, but it’s not represented as a result of the computation. Instead, it’s a side effect handled somewhere else in the catch block.

函数readFromDb的结果是一个错误,但未表示为计算结果。 相反,这是在catch块中其他地方处理的副作用。

This kind of code is very hard to parse and understand when there are multiple operations in a sequence which can produce errors (which is a very common case):

当序列中有多个操作会产生错误时,这种代码很难解析和理解(这是很常见的情况):

try {   data = readFromDB()   newData = doSomethingWithData(data)   isSuccess = putModifiedDataInDb(newData)} catch (e: Exception) {   // Which one of the operations caused this exception?   isSuccess = false}

If any one of these operations fail, it’s really hard to detect which one failed unless you put a try catch around each operation. Further, if future operations are dependent on the result of the previous operations, then you’d have to keep state of whether the previous operations have failed or not before executing future operations:

如果这些操作中的任何一个失败,那么除非您尝试尝试执行每个操作,否则很难检测到哪个失败。 此外,如果将来的操作取决于先前操作的结果,那么在执行将来的操作之前,您必须保持先前操作是否失败的状态:

fun updateDbData(): Boolean {    try {       data = readFromDb()    } catch (e: Exception) {       data = null    }        if(data == null) {        return false    }        try {       newData = doSomethingWithData(data)    } catch (e: Exception) {        newData = null    }        if(newData == null) {        return false    }        try {       return putModifiedDataInDb(newData)    } catch (e: Exception) {        return false    }     }

Ewww.

Ewww。

那么,我们如何从功能上改进它呢? (So how do we improve this in a functional way?)

Simple, let’s model failures as part of the result of the operation itself instead of an out of band process.

简单地说, 让我们将故障建模为操作本身结果的一部分,而不是带外处理。

Many functional languages also have exception handling, but it’s generally encouraged to ignore them. It’s much easier to reason about code where the failures and successes are a natural part of the computation itself.

许多功能语言也具有异常处理功能,但通常建议忽略它们。 对于代码来说,失败和成功是计算本身很自然的一部分就容易多了。

Let’s see what that looks like. Let’s make a Kotlin data class that encapsulates the result of our operation. This class will keep state of the success/failure state as well as the result data:

让我们看看它是什么样的。 让我们创建一个封装操作结果的Kotlin数据类 。 此类将保留成功/失败状态以及结果数据的状态:

data class Result(val data: Data = Data(), val success: Boolean = false)

success will tell us if the operation succeeded or failed. data is the data we need from the computation. We only access this if the success value is true(if the operation has succeeded).

success将告诉我们操作是成功还是失败。 data是我们从计算中获得的数据。 仅当success值为true (如果操作成功),我们才访问它。

Let’s use this to model our previous example:

让我们用它来建模我们之前的例子:

fun updateDbData(): Boolean {       val result1 = readFromDb()       if(!result1.success) {        return false    }        val result2 = doSomethingWithData(result1.data)       if(!result2.success) {        return false    }        val result3 = putModifiedDataInDb(result2.data)       if(!result3.success) {        return false    }        return true}

Much better.

好多了。

All we have done here is encapsulate computation errors as part of the natural computation.

我们在这里所做的只是封装计算错误作为自然计算的一部分。

Congratulations! We’ve just built a Maybe monad!

恭喜你! 我们刚刚建立了Maybe monad!

A Maybe monad represents the presence or absence of a value (hence the name maybe) which makes it perfect to represent computations that only have result data if they succeed.

Maybe monad表示值的存在或不存在(因此可能有一个名称),这使其非常适合表示仅在结果成功时才具有结果数据的计算。

But wait! Why do we need the success variable at all? If we use Kotlin’s nullable type to represent the Data object, we can ensure that data is only present if computation succeeds.

可是等等! 为什么我们根本需要success变量? 如果使用Kotlin的可为null的类型表示Data对象,则可以确保仅在计算成功的情况下才存在数据。

So our Result class is now:

所以我们的Result类现在是:

data class Result(val data: Data?)

and our function becomes:

我们的功能变为:

fun updateDbData(): Boolean {       val result1 = readFromDb()       if(result1.data == null) {        return false    }        val result2 = doSomethingWithData(result1.data)       if(result2.data == null) {        return false    }        val result3 = putModifiedDataInDb(result2.data)       if(result3.data == null) {        return false    }        return true}

You see? Kotlin’s optional types are just Maybe monads!

你看? Kotlin的可选类型只是可能单子!

We can make this code even nicer if we get rid of the data class altogether and just use the optional type directly:

如果我们完全摆脱了数据类,而直接使用可选类型,则可以使此代码更好。

fun updateDbData(): Boolean {    readFromDb()?. let {        doSomethingWithData(it)?.let {            putModifiedDataInDb(it)?.let {                return true            }        }    }        return false}

We are using Kotlin’s ?.let syntax which only executes a lambda if the variable it’s applied to is not null.

我们使用的是Kotlin的?.let语法,如果所应用的变量不为null,则仅执行lambda。

Neat huh?

整洁吗?

是的,但是什么是Monad? (Yeah, but what’s a Monad?)

Monads are computation builders. They encapsulate types, specific ways to combine those types, and operations on those types.

Monad是计算构建器。 它们封装类型,组合这些类型的特定方法以及对这些类型的操作。

For example, in our function above, Kotlin’s optional type can be used to encapsulate an operation result. When combined with the ?.let operator, it only allows the lambda to be executed if the result of the operation is non null. It allows us to express computation results and combine them in specific ways according to a defined ruleset.

例如,在上面的函数中,Kotlin的可选类型可用于封装运算结果。 当与?.let运算符结合使用时,仅当运算结果为非null时才允许执行lambda。 它使我们能够表达计算结果,并根据定义的规则集以特定方式组合它们。

Monads come from category theory, and to truly understand the mathematical meaning of them, we will have to study that meaning. The good news however, is that we don’t need to get a masters in math to use ‘em. A basic understanding will do for our purposes, and as we get more into FP, we can keep on increasing your knowledge.

Monad来自类别理论,要真正理解它们的数学含义,我们将必须研究该含义。 好消息是,我们不需要掌握数学才能使用'em。 基本了解将有助于我们的目标,并且随着我们对FP的深入了解,我们可以继续增加您的知识。

“两者皆有” 单子 (The ‘Either’ Monad)

The Maybe monad let’s us model the presence or absence of a result. But what about a computation that can have two valid result paths? For example, we might want to return a default value for a computation instead of an absent value like null.

Maybe monad让我们为结果的存在与否建模。 但是可以有两个有效结果路径的计算又如何呢? 例如,我们可能想返回一个默认的计算值,而不是缺少空值(如null)。

This is where the Either monad comes in. It can represent a good and bad value. Usually left is used to indicate a failure and right is used to indicate success.

这就是Either monad出现的地方。它可以代表goodbad价值。 通常, left用于指示失败, right用于指示成功。

Let’s see an example. Suppose we have a function getUser. If no user is present, it’ll give us an anonymous user. Otherwise it’ll give us the current logged in user.

让我们来看一个例子。 假设我们有一个功能getUser 。 如果没有用户在场,它将给我们一个匿名用户。 否则,它将为我们提供当前的登录用户。

We can model it as an Either like this:

我们可以将其建模为Either,如下所示:

data class Either(val left: AnonUser?, val right: CurrentUser?)

and we can use it in calling code like this:

我们可以在调用代码时使用它,如下所示:

fun updateProfileData(): Boolean {    val either = getUser()        if(either.left) {        // can't update profile for anon user        return false    }    else {        updateProfile(either.right)        return true    }}

更多资源 (More resources)

You can find plenty of explanations on monads around the web like this one. If you wanna go deep and learn FP along with monads, I’d recommend the excellent free book Learn You A Haskell For Great Good.

您可以在网络上像这样的单子上找到很多解释。 如果您想与monad一起学习FP,我会推荐一本非常好的免费书籍《 Learning A Haskell For Great Good》

The monad implementations I’ve describe here are incomplete and mostly for the purpose of understanding the concepts. You can find more robust implementations in projects like kotlin-monads.

我在这里描述的monad实现是不完整的,主要是为了理解这些概念。 您可以在诸如kotlin-monads之类的项目中找到更强大的实现。

摘要 (Summary)

Functional programming encourages treating errors as part of the computation itself and not as aberrations to the regular flow of control. This makes control flow easier to understand, handle, and test. We achieve this easily by representing computation results using Kotlin’s optional types or our own custom monad implementations.

函数式编程鼓励将错误视为计算本身的一部分,而不是作为常规控制流的异常。 这使控制流更易于理解,处理和测试。 通过使用Kotlin的可选类型或我们自己的自定义monad实现来表示计算结果,我们可以轻松实现此目标。

In the next and final part of this series, we’ll look at implementing a functional architecture on Android by tying together all the concepts we have learned so far.

在本系列的下一个也是最后一部分,我们将通过将到目前为止所学到的所有概念联系在一起,来研究在Android上实现功能体系结构。

If you liked this, click the ? below. I notice each one and I’m grateful for every one of them.

如果喜欢此,请单击“?”。 下面。 我注意到每个人,我感谢每个人。

For more musings about programming, follow me so you’ll get notified when I write new posts.

有关编程的更多信息,请关注我,以便在我撰写新文章时得到通知。

翻译自: https://www.freecodecamp.org/news/functional-programming-for-android-developers-part-4-b7e1d436a62b/

android 函数式编程

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值