monad_ScalaEither monad生存指南

monad

I started to work with Scala few months ago. One of the concepts that I had the most difficulties to understand is the Either monad. So, I decided to play around with it and better understand its power.

几个月前,我开始与Scala合作。 我最难理解的概念之一是Either monad。 因此,我决定试用它并更好地了解它的功能。

In this story I share what I’ve learned, hoping to help coders approaching this beautiful language.

在这个故事中,我分享了我学到的东西,希望能帮助编码人员接近这种美丽的语言。

要么单子 (The Either monad)

Either is one of the most useful monads in Scala. If you are wondering what a monad is, well… I cannot go into the details here, maybe in a future story!

Either都是Scala中最有用的单子之一。 如果您想知道单子是什么 ,那么……我可能在以后的故事中无法详细介绍!

Imagine Either like a box containing a computation. You work inside this box, until you decide to get the result out of it.

想象一下, Either像含有计算的盒子。 您需要在此框中进行操作,直到决定从中获取结果。

In this specific case, our Either box can have two “forms”. It can be (either) a Left or a Right, depending on the result of the computation inside it.

在这种特定情况下,我们的任意Either框都可以具有两个“表单”。 它可以是( LeftRight ,具体取决于其中的计算结果。

I can hear you asking: “OK, and what is it useful for?”

我听到你在问:“好,这对您有什么用?”

The usual answer is: error handling.

通常的答案是:错误处理。

We can put a computation in the Either, and make it a Left in case of errors, or a Right containing a result in case of success. The use of Left for errors, and Right for success is a convention. Let’s understand this with some code!

我们可以将计算放在Either ,如果有错误,则将其Left ;如果成功,则将其包含其中的结果Right 。 习惯上使用Left表示错误,使用Right表示成功。 让我们用一些代码来理解这一点!

In this snippet we are only defining an Either variable.

在此代码段中,我们仅定义一个Either变量。

We can define it as a Right containing a valid value, or as Left containing an error. We also have a computation that return an Either, meaning it can be a Left or a Right. Simple, isn’t it?

我们可以将其定义为包含有效值的Right或包含错误的Left 。 我们还有一个返回Either的计算, Either意味着它可以是LeftRight 。 很简单,不是吗?

左右投影 (Right and left projection)

Once we have the computation in the box, we may want to get the value out of it. I’m sure you expect to call a .get on the Either and extract your result.

一旦在框内进行了计算,我们可能想要从中获得价值。 我确定您希望在Either上调用.get并提取结果。

That’s not so simple.

那不是那么简单。

Think about it: you put your computation in the Either, but you don’t know if it resulted in a Left or a Right. So what should a .get call return? The error, or the value?

考虑一下:您将计算放在Either ,但是您不知道它是产生Left还是Right 。 那么.get调用应该返回什么? 错误或价值?

This is why to get the result you should make an assumption about the outcome of the computation.

这就是为什么要获得结果的原因,您应该对计算结果进行假设。

Here is where the projection comes into play.

这是投影起作用的地方。

Starting from an Either, you can get a RightProjection or a LeftProjection. The former means that you assume the computation resulted in a Right, the latter in a Left.

Either开始,您可以获得RightProjectionLeftProjection 。 前者意味着您假定计算得出了Right ,后者得出了Left

I know, I know… this may be a little confusing. It’s better to understand it with some code. After all, code always tells the truth.

我知道,我知道...这可能有点令人困惑。 最好通过一些代码来理解它。 毕竟, 代码总是说实话

That’s it. Note that when you try to get the result from a RightProjection, but it is a Left, you get an exception. The same goes for a LeftProjection and you have a Right.

而已。 请注意,当您尝试从RightProjection获得结果,但它是Left ,您将获得异常。 LeftProjection同样适用,并且您拥有Right

The cool thing is that you can map on projections. This means you can say: “assume it is a Right: do this with it”, leaving the Left unchanged (and the other way around).

很棒的事情是您可以映射投影。 这意味着您可以说:“假设它是右手:用它来做到这一点”,而Left保持不变(反之亦然)。

从选项到任一 (From Option to Either)

Option is another common way to deal with invalid values.

Option是处理无效值的另一种常用方法。

An Option can have a value or be empty (it’s value is Nothing). I bet you noticed a similarity with Either… It’s even better, because we can actually transform an Option into an Either! Code time!

一个Option可以有一个值或为空(它的值为Nothing )。 我敢打赌,您注意到了与Either的相似之处……更好,因为我们实际上可以将Option转换为Either ! 编码时间!

It is possible to transform an Option to a Left or a Right. The resulting side of the Either will contain the value of the Option if it is defined. Cool. Wait a minute… What if the Option is empty? We get the other side, but we need to specify what we expect to find in it.

可以将Option转换为LeftRight 。 如果定义,则Either一方的结果面都将包含Option的值。 凉。 请稍等...如果Option为空怎么办? 我们得到了另一面,但我们需要指定期望在其中找到的内容。

反了 (Inside out)

Either is magic, we all agree on that. So we decide to use it for our uncertain computations. A typical scenario when doing functional programming is the mapping a function on a List of elements, or on a Map. Let’s do it with our fresh new Either-powered computation…

Either是魔术,我们都同意这一点。 因此,我们决定将其用于不确定的计算。 执行函数式编程的一种典型情况是将函数映射到元素ListMap 。 让我们用全新的以Either动力的计算来完成它…

Huston, we have a “problem” (ok, it’s not a BIG problem, but it is a bit uncomfortable). It would be better to have the collection inside the Either than lots of Either inside the collection. We can work on that.

休斯顿,我们有一个“问题”(好吧,这不是一个大问题,但这有点不舒服)。 这将是最好有内部的集合Either比很多Either在内部集合。 我们可以解决这个问题。

清单 (List)

Let’s start with List. First we reason about it, then we can play with code.

让我们从List开始。 首先我们对此进行推理,然后我们可以使用代码。

We have to extract the value from the Either, put it in the List, and put the list inside an Either. Good, I like it.

我们必须从Either提取值,将其放入List ,然后将列表放入Either 。 很好我喜欢。

The point is that we can have a Left or a Right, so we need to handle both cases. Until we find a Right, we can put its value inside a new List. We proceed this way accumulating every value in the new List.

关键是我们可以有LeftRight ,因此我们需要处理两种情况。 在找到Right ,我们可以将其值放入新的List 。 我们以这种方式累积新List中的每个值。

Eventually we will reach the end of the List of Either, meaning we have a new List containing all the values. We can pack it in a Right and we are done. This was the case where our computation didn’t return an Error inside a Left.

最终,我们将到达Either List的末尾, Either意味着我们有了一个包含所有值的新List 。 我们可以将其包装在Right然后完成。 在这种情况下,我们的计算没有在Left内部返回Error

If this happens, it means that something went wrong in our computation, so we can return the Left with the Error. We have the logic, now we need the code.

如果发生这种情况,则意味着我们的计算出现了问题,因此我们可以使用Error返回Left 。 我们有逻辑,现在我们需要代码。

地图 (Map)

The work on Map is quite simple once we have done the homework for the List (despite needing to make it generic):

一旦我们完成了List的作业(尽管需要使其通用),在Map上的工作就非常简单:

  • Step one: transform the Map in a List of Either containing the tuple (key, value).

    第一步:在包含元组(键,值)的EitherList中转换Map

  • Step two: pass the result to the function we defined on List.

    第二步:将结果传递给我们在List定义的函数。

  • Step three: transform the List of tuples inside the Either in a Map.

    第三步:在MapEither中转换元组List

Easy Peasy.

十分简单。

让我们变得优雅:一个有用的隐式转换器 (Let’s get classy: a useful implicit converter)

We introduced Either and understood it is useful for error handling. We played a bit with projections. We saw how to pass from an Option to an Either. We also implemented some useful functions to “extract” Either from List and Map. So far so good.

我们介绍了Either并了解它对于错误处理很有用。 我们做了一些预测。 我们看到了如何从Option传递到Either 。 我们还实现了一些有用的功能来“提取” ListMap Either 。 到目前为止,一切都很好。

I would like to conclude our journey in the Either monad going a little bit further. The utility functions we defined do their jobs, but I feel like something is missing…

我想结束我们在Either monad的旅程,走得更远。 我们定义的效用函数可以完成其工作,但我感觉有些东西丢失了……

It would be amazing to do our conversion directly on the collection. We would have something like myList.toEitherList or myMap.toEitherMap. More or less like what we do with Option.toRight or Option.toLeft.

直接在集合上进行转换将是惊人的。 我们会有类似myList.toEitherListmyMap.toEitherMap东西。 或多或少像我们对Option.toRightOption.toLeft

Good news: we can do it using implicit classes!

好消息:我们可以使用隐式类来做到这一点!

Using implicit classes in Scala lets us extend the capabilities of another class.

在Scala中使用隐式类可以让我们扩展另一个类的功能。

In our case, we extend the capability of List and Map to automagically “extract” the Either. The implementation of the conversion is the same we defined before. The only difference is that now we make it generic. Isn’t Scala awesome?

在我们的案例中,我们扩展了ListMap的功能,以自动“提取” Either 。 转换的实现与我们之前定义的相同。 唯一的区别是,现在我们使它通用。 Scala很棒吗?

Since this can be a useful utility class, I prepared for you a gist you can copy and paste with ease.

由于这可能是有用的实用程序类,因此我为您准备了一个要点,您可以轻松复制和粘贴。

object EitherConverter {
  implicit class EitherList[E, A](le: List[Either[E, A]]){
    def toEitherList: Either[E, List[A]] = {
      def helper(list: List[Either[E, A]], acc: List[A]): Either[E, List[A]] = list match {
        case Nil => Right(acc)
        case x::xs => x match {
          case Left(e) => Left(e)
          case Right(v) => helper(xs, acc :+ v)
        }
      }

      helper(le, Nil)
    }
  }

  implicit class EitherMap[K, V, E](me: Map[K, Either[E, V]]) {
    def toEitherMap: Either[E, Map[K, V]] = me.map{
        case (k, Right(v)) => Right(k, v)
        case (_, e) => e
      }.toList.toEitherList.map(l => l.asInstanceOf[List[(K, V)]].toMap)
  }
}
结论 (Conclusion)

That’s all folks. I hope this short story may help you to better understand the Either monad.

那是所有人。 我希望这个简短的故事可以帮助您更好地理解Either monad。

Please note that my implementation is quite simple. I bet there are more complex and elegant ways to do the same thing. I’m a newbie in Scala and I like to KISS, so I prefer readability over (elegant) complexity.

请注意,我的实现非常简单。 我敢打赌,有更多更复杂,更优雅的方法可以做同样的事情。 我是Scala的新手,并且喜欢KISS ,所以我更喜欢可读性而不是(优雅的)复杂性。

If you have a better solution, especially for the utility class, I will be happy to see it and learn something new! :-)

如果您有更好的解决方案,尤其是对于实用程序类,我将很高兴看到它并学习新知识! :-)

翻译自: https://www.freecodecamp.org/news/a-survival-guide-to-the-either-monad-in-scala-7293a680006/

monad

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值