scala – 用适用函子总结选项列表
我有一个列表[选项[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. 一些功能将填充我的列表,我想要进一步处理它,尽可能容易,而不检查其中一个元素是否为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]],我们可以随意使用,取决于我们想要的行为,即:在跳过列表时,跳过“否定”或“快速失败”. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |