加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 用适用函子总结选项列表

发布时间:2020-12-16 19:01:36 所属栏目:安全 来源:网络整理
导读:我有一个列表[选项[Int]],并想使用应用程序函子来总结. 从[1]我明白这应该是如下 import scalaz._import Scalaz._List(1,2,3).map(some(_)).foldLeft(some(0))({ case (acc,value) = (acc |*| value){_+_}}) 然而,我根本无法弄清楚正确的写法. 如果有人可以
我有一个列表[选项[Int]],并想使用应用程序函子来总结.
从[1]我明白这应该是如下

import scalaz._
import Scalaz._

List(1,2,3).map(some(_)).foldLeft(some(0))({
    case (acc,value) => (acc <|*|> value){_+_}
})

然而,我根本无法弄清楚正确的写法.
如果有人可以帮助我,我会很高兴.

非常感谢你

[1] How to combine Option values in Scala?

编辑

感谢所有伟大的答案.

如果列表中有任何无,我希望它返回None.
我试图用Option / E来替换Null / Exception,看看我是否可以生成一些可用的代码.

一些功能将填充我的列表,我想要进一步处理它,尽可能容易,而不检查其中一个元素是否为None.它应该像异常一样工作,我不必在我的函数中检查它,而是让调用者照顾它.

解决方法

如果您有Option [T],如果有一个Monoid for T,那么有一个Monoid [Option [T]]:

implicit def optionTIsMonoid[T : Monoid]: Monoid[Option[T]] = new Monoid[Option[T]] {
  val monoid = implicitly[Monoid[T]]
  val zero = None
  def append(o1: Option[T],o2: =>Option[T]) = (o1,o2) match {
    case (Some(a),Some(b)) => Some(monoid.append(a,b))
    case (Some(a),_)       => o1
    case (_,Some(b))       => o2
    case _                  => zero
  }
}

一旦你配备了这个,你可以使用sum(比foldMap(身份),如@missingfaktor建议的):

List(Some(1),None,Some(2),Some(3),None).asMA.sum === Some(6)

UPDATE

我们实际上可以使用应用程序来简化上面的代码:

implicit def optionTIsMonoid[T : Monoid]: Monoid[Option[T]] = new Monoid[Option[T]] {
   val monoid = implicitly[Monoid[T]]
   val zero = None
   def append(o1: Option[T],o2: =>Option[T]) = (o1 |@| o2)(monoid.append(_,_))
}

这让我觉得我们甚至可以进一步推广到:

implicit def applicativeOfMonoidIsMonoid[F[_] : Applicative,T : Monoid]: Monoid[F[T]] = 
  new Monoid[F[T]] {
    val applic = implicitly[Applicative[F]]
    val monoid = implicitly[Monoid[T]]

    val zero = applic.point(monoid.zero)
    def append(o1: F[T],o2: =>F[T]) = (o1 |@| o2)(monoid.append(_,_))
  }

像这样,你甚至可以列出列表,树木名单…

UPDATE2

澄清问题让我意识到上述更新不正确!

首先,optionTIsMonoid(如重构的)不等同于第一个定义,因为第一个定义将跳过无值,而第二个定义将在输入列表中有一个None时返回None.但在这种情况下,这不是一个Monoid!的确,Monoid [T]必须遵守Monoid定律,零点必须是identity元素.

我们本应该:

zero    |+| Some(a) = Some(a)
Some(a) |+| zero    = Some(a)

但是,当我提出使用“选择权申请”的Monoid [Option [T]]的定义时,情况并非如此:

None    |+| Some(a) = None
None    |+| None    = None
=> zero |+| a      != a

Some(a) |+| None    = zero
None    |+| None    = zero
=> a    |+| zero   != a

修复并不难,我们需要改变零的定义:

// the definition is renamed for clarity
implicit def optionTIsFailFastMonoid[T : Monoid]: Monoid[Option[T]] = 
  new Monoid[Option[T]] {
    monoid = implicitly[Monoid[T]]
    val zero = Some(monoid.zero)
    append(o1: Option[T],_))
  }

在这种情况下,我们将(以T为Int):

Some(0) |+| Some(i) = Some(i)
Some(0) |+| None    = None
=> zero |+| a       = a

Some(i) |+| Some(0) = Some(i)
None    |+| Some(0) = None
=> a    |+| zero    = zero

证明身份法被证实(我们也应该验证associative法律是否得到尊重,…).

现在我们有2个Monoid [Option [T]],我们可以随意使用,取决于我们想要的行为,即:在跳过列表时,跳过“否定”或“快速失败”.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读