处理 Option 和 Either 类型 - 惯用转换?
Posted
技术标签:
【中文标题】处理 Option 和 Either 类型 - 惯用转换?【英文标题】:Dealing with Option and Either types - idiomatic conversions? 【发布时间】:2011-11-22 07:54:10 【问题描述】:我可能在文档中遗漏了一些正确的东西,但我无法真正理解它 - 我一直在通过反复试验来自学 Scala。
给定一个函数f: A => C
,执行以下转换的惯用方法是什么?
Either[A, B] -> Either[C, B]
Either[B, A] -> Either[B, C]
(如果我有两个这样的函数,并且想转换两边,我可以一次完成还是应该顺序应用两次成语?)
Option[A] -> Option[C]
(我感觉这应该以某种方式使用for (...) yield
;我可能只是对此一无所知,当我看到答案时会觉得很傻)
究竟是Either
的“投影”吗?
【问题讨论】:
从下面的评论中,您似乎将Either
与Pair
、Tuple2
混淆了。情况并非如此:Either
只能包含 one 值。从某种意义上说,它类似于 C 中的union
,只是你知道实际存储的是哪个成员。
我知道这一点,但我仍然对一个预测被混入其中感到困惑。我并没有真正表达清楚。
【参考方案1】:
您可以选择:
either.left.map(f)
或一个:
either.right.map(f)
您也可以使用理解:for (x <- either.left) yield f(x)
这是一个更具体的例子,在 Either[Boolean, Int]
上执行 map
:
scala> val either: Either[Boolean, Int] = Right(5)
either: Either[Boolean, Int] = Right(5)
scala> val e2 = either.right.map(_ > 0)
either: Either[Boolean, Boolean] = Right(true)
scala> e2.left.map(!_)
either: Either[Boolean, Boolean] = Right(true)
编辑:
它是如何工作的?假设您有一个Either[A, B]
。调用left
或right
会创建一个LeftProjection
或RightProjection
对象,该对象是一个包含Either[A, B]
对象的包装器。
对于left
包装器,应用带有函数f: A => C
的后续map
将Either[A, B]
转换为Either[C, B]
。它通过在后台使用模式匹配来检查Either
是否实际上是Left
。如果是,它会创建一个新的Left[C, B]
。如果没有,它只会更改创建一个具有相同基础值的新Right[C, B]
。
对于 right
包装器,反之亦然。实际上,说 either.right.map(f)
意味着 - 如果任一 (Either[A, B]
) 对象包含 Right
值,则映射它。否则,保持原样,但更改任一对象的类型 B
,就像您已映射它一样。
所以从技术上讲,这些预测只是包装。从语义上讲,它们是一种表示您正在做某事的方式,假设存储在Either
对象中的值是Left
或Right
。如果这个假设是错误的,映射什么也不做,但是类型参数会相应地改变。
【讨论】:
请分解一下这对我有什么作用?跟预测有关系吗?显然,.left
和 .right
与其他具有库“pair”类型的语言不同,它们只会分别访问 [A] 和 [B] 类型的成员。
我已经编辑了答案,以解释一些幕后发生的事情。但是,要么不是对,要么不是元组类型,也称为交集类型 - A x B
。它拥有 [A] 或 [B] 类型的成员 - A V B
。这意味着您不能像在元组中那样安全地访问任一成员,因为只有一个成员存在。
...漂亮。那么选项呢?只需for (x <- option) yield f(x)
,因为 Option 已经是可迭代的?
@Karl Option
不是Iterable
,但它实现了方法map
,这样就够了。
这里的问题是您需要提供 2 个映射函数来执行 Either
的实际映射,因为里面有 2 种可能的 types 值,并且你不知道它是什么。你可以这样做:e.left.map(!_).right.map(_ * 2)
。你能从那里去寻找循环风格吗?可能是。让我考虑一下..【参考方案2】:
给定f: A=>B
和xOpt: Option[A]
,xOpt map f
会生成您需要的Option[B]
。
给定f: A=>B
和xOrY: Either[A, C]
,xOrY.left.map(f)
生成您正在寻找的Either
,仅映射第一个组件;同样,您可以处理RightProjection
的Either
。
如果您有两个函数,则可以为两个组件定义映射,xOrY.fold(f, g)
。
【讨论】:
【参考方案3】:val e1:Either[String, Long] = Right(1)
val e2:Either[Int,Boolean] = e1.left.map(_.size).right.map( _ >1 )
// e2: Either[Int,Boolean] = Right(false)
【讨论】:
以上是关于处理 Option 和 Either 类型 - 惯用转换?的主要内容,如果未能解决你的问题,请参考以下文章
在 Flutter 中解压 Option<Either<T,T>>