我想知道为什么 scala.Option 没有方法 fold 像这样的定义:

fold(ifSome: A => B , ifNone: => B)

相当于

map(ifSome).getOrElse(ifNone)

没有比使用更好的 map + getOrElse?

有帮助吗?

解决方案

你可以做:

opt foldLeft (els) ((x, y) => fun(x))

或者

(els /: opt) ((x,y) => fun(x))

(两种解决方案都将评估 els 按价值,这可能不是您想要的。谢谢 雷克斯·克尔(Rex Kerr) 指向它。)

编辑:

但是您真正想要的是Scalaz的 ca态 cata (基本上是 fold 不仅可以处理 Some 价值,但也映射 None 部分,这是您描述的)

opt.cata(fun, els)

定义为(哪里 value 是PIMPED选项值)

def cata[X](some: A => X, none: => X): X = value match {
  case None => none
  case Some(a) => some(a)
}

等同于 opt.map(some).getOrElse(none).

尽管我应该指出,您只能在表达“更自然”的方式时使用CATA。在很多情况下,一个简单 mapgetOrElse 足够,尤其是在涉及潜在链接大量的时候 maps。 (尽管您也可以连锁 fun当然,具有功能组成的s - 取决于您是否要专注于功能组成还是值转换。)

其他提示

我个人找到了类似的方法 cata 随着论点经常过分,这两个封闭。你真的会赢得可读性吗 map + getOrElse?想到您的代码的新来者:他们会做什么

opt cata { x => x + 1, 0 }

你真的认为这比

opt map { x => x + 1 } getOrElse 0

实际上,我会说,这两个都不比旧的旧

opt match {
  case Some(x) => x + 1
  case None => 0
}

与往常一样,额外的抽象不会给您带来好处并适得其反。

终于添加了 在Scala 2.10中, ,带签名 fold[B](ifEmpty: => B)(f: A => B): B.

不幸的是,这有一个共同的负面后果: B 仅根据基于 ifEmpty 争论,实际上通常更狭窄。例如(标准库中已经有正确的版本,这仅用于演示)

 def toList[A](x: Option[A]) = x.fold(Nil)(_ :: Nil)

Scala将推断 B 成为 Nil.type 而不是想要的 List[A] 并抱怨 f 不返回 Nil.type. 。相反,您需要一个

 x.fold[List[A]](Nil)(_ :: Nil)
 x.fold(Nil: List[A])(_ :: Nil)

这使得 fold 不等于相应 match.

如Debilski所述,您可以使用Scalaz的 OptionW.cata 或者 fold. 。正如杰森(Jason)评论的那样,命名参数使它看起来不错:

opt.fold { ifSome = _ + 1, ifNone = 0 }

现在,如果您想要的价值 None 情况是 mzero 对于一些 Monoid[M] 而且您有一个功能 f: A => M 为了 Some 情况,您可以做到这一点:

opt foldMap f

所以,

opt map (_ + 1) getOrElse 0

变成

opt foldMap (_ + 1)

我自己觉得 Option 应该有一个 apply 方法将是语态性。这样,您就可以做到这一点:

opt { _ + 1, 0 }

或者

opt { some = _ + 1, none = 0 }

实际上,对于所有代数数据结构来说,这都是很好的。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top