Scala 带选项参数的二元运算符
在scala中,如何定义两个选项参数上的加法?具体来说,让我们假设它们是Scala 带选项参数的二元运算符,scala,Scala,在scala中,如何定义两个选项参数上的加法?具体来说,让我们假设它们是Int类型的包装器(我实际上正在处理double的映射,但这个示例更简单) 我尝试了以下操作,但它只是给了我一个错误: def addOpt(a:Option[Int], b:Option[Int]) = { a match { case Some(x) => x.get case None => 0 } + b match { case Some(y) =
Int
类型的包装器(我实际上正在处理double的映射,但这个示例更简单)
我尝试了以下操作,但它只是给了我一个错误:
def addOpt(a:Option[Int], b:Option[Int]) = {
a match {
case Some(x) => x.get
case None => 0
} + b match {
case Some(y) => y.get
case None => 0
}
}
编辑以添加:
在我的实际问题中,我添加了两个贴图,它们代表稀疏向量。因此None case返回Map[Int,Double],而+实际上是一个++(在stackoverflow.com/a/7080321/614684上有调整)如果它们都默认为0,则不需要模式匹配:
def addOpt(a:Option[Int], b:Option[Int]) = {
a.getOrElse(0) + b.getOrElse(0)
}
这将适用于任意数量的输入。幺半群
当你意识到你可以站在巨人的肩膀上,利用共同的抽象和为使用它们而建立的库时,你可能会发现生活变得容易多了。为此,这个问题基本上是关于处理
幺半群(有关这方面的更多信息,请参见下面的相关问题),该库被称为
使用scalaz FP,这只是:
def add(a: Option[Int], b: Option[Int]) = ~(a |+| b)
更重要的是,这适用于任何幺半群M:
def add[M: Monoid](a: Option[M], b: Option[M]) = ~(a |+| b)
更有用的是,它可以处理放置在可折叠容器中的任意数量的代码:
def add[M: Monoid, F: Foldable](as: F[Option[M]]) = ~as.asMA.sum
请注意,除了明显的Int
、String
、Boolean
之外,还有一些非常有用的幺半群:
Map[A,B:Monoid]
A=>(B:Monoid)
选项[A:Monoid]
scala> some(some(some(1))) #:: some(some(some(2))) #:: Stream.empty
res0: scala.collection.immutable.Stream[Option[Option[Option[Int]]]] = Stream(Some(Some(Some(1))), ?)
scala> ~res0.asMA.sum
res1: Option[Option[Int]] = Some(Some(3))
一些相关问题 什么是幺半群 幺半群是一种类型
M
,对于该类型,在该操作下存在关联二进制操作(M,M)=>M
和标识I
,使得mplus(M,I)==M==mplus(I,M)
对于类型M
的所有M
什么是|+|
这只是mplus
二进制操作的scalaz速记(或ASCII-madness,ymmv)
什么是~
如果M
是幺半群,它是一个一元运算符,意思是“或标识”,scalaz库将其改装为Option[M]
(使用scala的隐式转换)。显然,非空选项返回其内容;空选项将替换为幺半群的标识
问:asMA.sum
是什么
foldLeft
基本上是一种可以折叠的数据结构(例如foldLeft
)。回想一下,foldLeft
采用种子值和操作组成连续计算。在求和幺半群的情况下,种子值是标识I
,操作是mplus
。因此,您可以在可折叠的[M:Monoid]上调用asMA.sum
。您可能需要使用asMA
,因为名称与标准库的sum
方法冲突
一些参考资料
- 我的一次演讲给出了在野外使用幺半群的实际例子
您没有以正确的方式提取选项的内容。当您与
case Some(x)
匹配时,x
是选项(键入Int
)中的值,您不会调用get
。照办
case Some(x) => x
无论如何,如果您想要内容或默认值,a.getOrElse(0)
更方便def addOpt(ao:Option[Int],bo:Option[Int])=
def addOpt(ao: Option[Int], bo: Option[Int]) =
for {
a <- ao
b <- bo
} yield a + b
为了{
a在我的实际问题中,它们没有。我正在添加两个映射,它们是稀疏向量的替代。如果两个映射都没有默认值,那么在这种情况下就不能使用选项,因为它们中的一个或两个都可能是未定义的。如果我将它们默认为Map[Int,Double](这就是它们的实际值),而+
实际上是+
(在.FWIW处进行了调整,为了使这项工作适用于Map[Int,Double]
,它只需def addOpts(xs:Option[Map[Int,Double]]*)=xs.flatte.foldLeft(Map.empty[Int,Double]){{code++}
或者同时适用于这两者的scalaz版本:def addOpts[T:Monoid](xs:Option[T]*)=xs.flatte.asMA.sum
您没有以正确的方式提取选项的内容。当您匹配case Some(x)时,x是选项内的值(键入Int),您不会调用get。case Some(x)=>x。总之,如果您想要内容或默认值,a.getOrElse(0)更方便。@didierd谢谢!这是我需要的答案。你能转换成一个答案吗?我会选择你的答案。强制性参考:什么是~
做的?我认为你应该更好地解释成分。对于我们中使用scalaz 7的人,我相信等效的答案是,~res0.suml
谢谢!这非常有用。我很抱歉尽管使用@didierd来指出scala抱怨的原因。@JasonMond仔细看看这个幺半群的东西,它很有用,我保证!有人应该在类路径上用scalaz设置一个“simplyscala”,以便于原型化我认为~
应该是“或零”,而不是“或标识”。这返回选项[Int]
而不是Int
。此外,如果ao
或bo
为None
,则返回None
,这不是期望的结果。你是对的,它不会产生OP代码的预期结果,但是我要说它确实解决了问题标题的精神。虽然它不像origi那样返回0最后回答,只需添加getOrElse即可
def addOpt(ao: Option[Int], bo: Option[Int]) =
for {
a <- ao
b <- bo
} yield a + b